0

バックエンドを呼び出す前に、userId と authToken を設定する必要があるシングルトン クラス APIClient があります。

現在、userId と authToken を NSUserDefaults に保存しています。新規インストールの場合、これらの値は存在しないため、サーバーに照会します。

現在、ViewController の viewDidLoad メソッドには、これらの値が存在しない場合にサーバーに手動でクエリを実行するコードがあります。

このクラスを「うまく機能させる」ことに興味があります。これにより、クライアントが初期化されているかどうかをチェックし、そうでない場合はサーバーへの呼び出しを開始し、適切な userId と authToken を設定することを意味します-すべて手動の干渉なしで。

これは、次の理由により、かなりトリッキーであることが証明されています。

  1. #iphonedev の人々から、ネットワーク操作のためにメインスレッドをフリーズする必要がある場合、OS がアプリを強制終了すると言われたため、asyncObtainCredentials を同期化できません。
  2. 現時点では、asyncObtainCredential の非同期性のため、最初の呼び出しは常に失敗します。Nil が返され、最初の呼び出しは常に失敗します。

この問題の回避策を知っている人はいますか?

`

@interface APIClient ()
@property (atomic) BOOL initialized;
@property (atomic) NSLock *lock;
@end

@implementation APIClient

#pragma mark - Methods

- (void)setUserId:(NSNumber *)userId andAuthToken:(NSString *)authToken;
{
    self.initialized = YES;
    [self clearAuthorizationHeader];
    [self setAuthorizationHeaderWithUsername:[userId stringValue] password:authToken];
}

#pragma mark - Singleton Methods

+ (APIClient *)sharedManager {
    static dispatch_once_t pred;
    static APIClient *_s = nil;

    dispatch_once(&pred, ^{
        _s = [[self alloc] initWithBaseURL:[NSURL URLWithString:SERVER_ADDR]];
        _s.lock =[NSLock new] ;
    });

    [_s.lock lock];
    if (!(_s.initialized)) {
        NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
        NSNumber *userId = @([prefs integerForKey:KEY_USER_ID]);
        NSString *authToken = [prefs stringForKey:KEY_AUTH_TOKEN];

        // If still doesn't exist, we need to fetch
        if (userId && authToken) {
            [_s setUserId:userId andAuthToken:authToken];
        } else {
            /*
             * We can't have obtainCredentials to be a sync operation the OS will kill the thread
             * Hence we will have to return nil right now.
             * This means that subsequent calls after asyncObtainCredentials has finished
             * will have the right credentials.
             */
            [_s asyncObtainCredentials:^(NSNumber *userId, NSString *authToken){
                [_s setUserId:userId andAuthToken:authToken];
            }];
            [_s.lock unlock];
            return nil;
        }
    }
    [_s.lock unlock];

    return _s;
}

- (void)asyncObtainCredentials:(void (^)(NSNumber *, NSString *))successBlock {

    AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:SERVER_ADDR]];
    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:[OpenUDID value], @"open_udid", nil];
    NSMutableURLRequest *request = [client requestWithMethod:@"GET" path:@"/get_user" parameters:params];

    AFJSONRequestOperation *operation = \
    [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
        ... 

        // Do not use sharedManager here cause you can end up in a deadlock
        successBlock(userId, authToken);

    } failure:^(NSURLRequest *request , NSURLResponse *response , NSError *error , id JSON) {
        NSLog(@"obtain Credential failed. error:%@ response:%@ JSON:%@",
              [error localizedDescription], response, JSON);
    }];

    [operation start];
    [operation waitUntilFinished];
}
4

1 に答える 1