[英]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.