2016-09-05 18 views
0

リモート呼び出しをバックエンドに集中するためのクラスを作成しています。 コールはoauthで認証されなければならないので、各メソッドで、まず自分のトークンがvalideかどうかをチェックし、そうでなければリフレッシュするように要求します。並行メソッドの実行とブロックを防止する

それぞれの方法には、次のようになります方法

​​

checkOAuthTokenAndRunは、トークンの有効性を確認し、必要に応じて新しいものを要求します。 私が問題になっているのは、checkOAuthTokenAndRunが同時に呼び出されないようにして、リフレッシュされている(書き込まれている)ときに資格情報を読み取らないようにすることです。

私はNSLockを試みたが、ブロック(マルチスレッド)で、私は次のエラーを取得する:あなたが見ての通り、

- (void)checkOAuthTokenAndRun:(void (^)())action orFail:(nullable void(^)(AFHTTPRequestOperation * __nullable operation, NSError * __nullable error))failure 
{ 
    NSLog(@"lock oauth check/refresh"); 
    [oauthLock lock]; 

    if (credential == nil || [credential isExpired]) 
    { 
     NSLog(@"Credentials are null or expired"); 

     if (credential == nil || credential.refreshToken == nil) 
     { 
      NSLog(@"Credentials are null or anonymous+expired"); 
      [self getAnonymousCredentialsAndRun:^{ 

       NSLog(@"unlock oauth"); 
       [oauthLock unlock]; 
       action(); 

      } orFail:^(AFHTTPRequestOperation * _Nullable operation, NSError * _Nullable error) { 

       NSLog(@"unlock oauth"); 
       [oauthLock unlock]; 
       failure(operation, error); 

      }]; 
     } 
     else 
     { 
      NSLog(@"Credentials are expired"); 

      AFOAuth2Manager *OAuth2Manager = [[AFOAuth2Manager alloc] initWithBaseURL:[NSURL URLWithString:BaseURL] clientID:clientId secret:clientSecret]; 

      [OAuth2Manager authenticateUsingOAuthWithURLString:@"/oauth/v2/token" refreshToken:credential.refreshToken success:^(AFOAuthCredential *_credential) { 
       credential = _credential; 

       NSLog(@"Received refreshed token"); 

       [AFOAuthCredential storeCredential:credential 
           withIdentifier:OAuthProviderIdentifier]; 

       NSLog(@"unlock oauth"); 
       [oauthLock unlock]; 

       action(); 

      } failure:^(NSError *error) { 

       NSLog(@"Failed refreshing oauth token (%@)", [error localizedDescription]); 

       // remove refresh token 
       NSLog(@"Unable to get oauth token, delete credentials (%@)", [error localizedDescription]); 
       [AFOAuthCredential deleteCredentialWithIdentifier:OAuthProviderIdentifier]; 

       credential = nil; //[AFOAuthCredential retrieveCredentialWithIdentifier:OAuthProviderIdentifier]; 

       NSLog(@"unlock oauth"); 
       [oauthLock unlock]; 

       failure(nil, error); 
      }]; 
     } 
    } 
    else { // run the action 
     NSLog(@"Credentials are valid (%@)", (credential.refreshToken.length ? @"refresh token defined" : @"refresh token not defined")); 

     NSLog(@"unlock oauth"); 
     [oauthLock unlock]; 
     action(); 
    } 
} 

私が使用しています:ここで

*** -[NSLock lock]: deadlock (<NSLock: 0x7ffd9313d9b0> '(null)') 

は、完全なcheckOAuthTokenAndRun方法でありますこれがデッドロックを取得する理由であるかどうかはわかりません。

はもう一度、私はあなたの助けを

おかげ

+0

約束をチェックしてください。基本的な考え方は、トークンを検証することが約束になることです。他のすべての要求は、それが達成されると、複数回実行されないその約束を断ち切ります。セッション中にトークンを無効にすることができる場合は、約束を無効にする方法を考え出す必要があります。私は現在の図書館にこれのための施設がないと確信していません。 (1つの実装として、FBからのBoltsフレームワークを参照してください) – Avi

+0

@Aviありがとう、PromiseKitを試してみましたが、音は良いですが、トークンメソッドの同時アクセスをロックすることはできません... – liilo

答えて

0

ネットワーク呼び出しが同時であり、彼らは同時である必要はありcheckOAuthTokenAndRun方法の同時実行を防ぎたいです。あなたのコードの問題は、それ自体が並行している別のメソッドの中で並行メソッドと呼ばれていることです。あなたの問題への解決:

最初にメソッドを呼び出すと、成功した場合(ブロックからの応答)、メソッドgetRemoteDataAndRunを呼び出します。

[self checkOAuthTokenAndRun:^{ 

    if(success){ 
     [self getRemoteDataAndRun:^{ 

      }] 
    } 
    } orFail:failure]; 

//上記のコードスニペットは、問題を解決するための単なる例です。ブロックパラメータを再設計する必要があります

+0

はい、まさに私がやっていることです。コードは成功と失敗のブロックで「アクション」メソッド(「getUserComments」と言う)に埋め込まれているため、すべてのアクションメソッドが同時にcheckOAuthTokenAndRunを呼び出さないようにしたい – liilo

関連する問題