簡體   English   中英

等待異步調用在完成塊中完成

[英]Waiting for an asyncronous call to finish within a completion block

我目前正在使用POC應用程序, 之前我已經在此處發布過該應用程序。 如果服務器給我一個401錯誤(未經授權),我正在嘗試處理身份驗證令牌的自動刷新。

這是我的演示函數,它從服務器請求一些信息(我可以故意向其發送有效/無效的身份驗證令牌)

NSInteger retryAttempts = 0;
NSInteger retryMax = 1;

- (void) requestDataForUser {
    NSLog(@"requestDataForUser - Called");

    //Indicate Network Activity
    dispatch_async(dispatch_get_main_queue(), ^{
        [UIApplication sharedApplication].networkActivityIndicatorVisible = TRUE;
    });

    //Build request URL String
    NSString *requestString = [NSString stringWithFormat:@"%@%@%@",baseURL,requestURL,@"3"];//Change to allow change in username here.

    //Get auth token
    NSString *accessToken = [SAMKeychain passwordForService:kServer account:kKeyAccessToken];
    NSString *requestAuthorization = [NSString stringWithFormat:@"%@ %@", @"Bearer", accessToken];

    //Initialize url request
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];

    //Set the url for the request
    [request setURL:[NSURL URLWithString:requestString]];

    //Set HTTP method for request
    [request setHTTPMethod:@"GET"];

    //Set HTTP header field with the authorization token
    [request setValue:requestAuthorization forHTTPHeaderField:@"Authorization"];

    //Create full request
    NSURLSession *session = [NSURLSession sharedSession];

    __weak typeof (self) weakSelf = self;
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                                completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){

                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"Status Code: %ld\n",(long)httpResponse.statusCode);

                                                    NSString *message = [NSHTTPURLResponse localizedStringForStatusCode:httpResponse.statusCode];
                                                    NSLog(@"Message: %@", message);

                                                    NSLog(@"requestDataForUser - Responce from server");

                                                    //Check for an error, if there is no error we proceed.
                                                    if (!error) {

                                                        if (retryAttempts <= retryMax) {
                                                        switch (httpResponse.statusCode) {
                                                            case 200 ... 299:
                                                                NSLog(@"SUCCESS");
                                                                NSLog(@"Performing any completion related functions!");
                                                                break;
                                                            case 401:
                                                                NSLog(@"401 Challenge - Retrying Authentication, Attempt %ld", (long)retryAttempts);

                                                                [weakSelf refreshAuth];
                                                                [weakSelf requestDataForUser];//retries this function

                                                                retryAttempts += 1;
                                                                break;

                                                        }}
                                                        else {
                                                            NSLog(@"401 Error Recieved - Retried credentials %ld time(s), please check your details are correct", (long)retryMax);
                                                            retryAttempts = 0; //Reset retry counter
                                                            //Alert controller?
                                                        }
                                                        //Get que and perform any UI changes
                                                        dispatch_async(dispatch_get_main_queue(), ^{

                                                            [UIApplication sharedApplication].networkActivityIndicatorVisible = FALSE;
                                                        });
                                                    }
                                                    else {
                                                        //Failed request
                                                        NSLog(@"requestDataForUser - error : %@", error.description);
                                                        dispatch_async(dispatch_get_main_queue(), ^{
                                                            [UIApplication sharedApplication].networkActivityIndicatorVisible = FALSE;
                                                        });
                                                    }
                                                }];
    [dataTask resume];

}

我遇到的問題在請求的401挑戰部分中。 我想做的是請求/刷新一個新令牌(在最后一次迭代中刷新,但是當前我的服務器在令牌刷新上有點命中/未命中,因此在此示例中我需要一個新令牌)。 因此,讓我們看一下我的服務器挑戰部分:

case 401:
         NSLog(@"401 Challenge - Retrying Authentication, Attempt %ld", (long)retryAttempts);
         [weakSelf refreshAuth];
         [weakSelf requestDataForUser];//retries this function
         retryAttempts += 1;
         break;

因此,我在這里打印嘗試次數,我可以手動設置重試此“塊”的次數,直到它放棄並向用戶拋出錯誤。 接下來,它將調用auth令牌,重試請求,並將retryAttempts增加1。

我的問題是,當我請求一個新令牌時,我是異步執行的,因此該請求被發送出去,然后我的函數重試自身(顯然沒有新令牌),然后拋出錯誤。 然后,我的令牌返回並打印到控制台,新令牌成功返回。

我看過信號量,但似乎無法使它們正常工作(因為我的requestAuthToken方法沒有完成塊)。 無論如何,我可以強制將身份驗證請求同步嗎?

我也嘗試過讓我的requestAuth方法返回BOOL並在401塊內循環bool,直到它變為true為止,但是它從未設置為true,而while循環永遠持續下去。

任何和所有幫助表示贊賞!

假設您可以更改requestAuth的實現,則將完成處理程序參數添加到requestAuth函數。
在requestAuth實現內部,在收到令牌后調用該處理程序。 然后在requestDataForUser中:

case 401:
     NSLog(@"401 Challenge - Retrying Authentication, Attempt %ld", (long)retryAttempts);
     [weakSelf refreshAuth withCompletionHandler:weakself.requestDataForUser];
     retryAttempts += 1;
     break;

否則,請使用NSOperationQueue並將最大並發操作設置為1:

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;

[queue addOperationWithBlock:^{
    [weakself requestAuth];
}];

[queue addOperationWithBlock:^{
    [weakself requestDataForUser];
}];

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM