将完成处理程序添加到仅 returns 完成的异步请求方法

Adding a completion handler to an asynchronous request method that only returns completion

所以我已经就此发布了两次,但我仍然很困惑 (post 1, )。

我想在调用另一个请求时收到 401 质询时触发身份验证请求。我的请求有一个完成块,因此它接收数据,然后在收到数据后可以做一些事情。

问题是,如果我收到 401,我想调用身份验证,然后重试我的请求。我收到 的答复说我应该向我的 auth 方法添加一个完成处理程序,以便它可以调用原始请求。问题是我不知道如何只向我的方法添加一个完成块。我查找了块并尝试了 ray wenderlich 教程,但似乎一切都在 returning 某些东西或传递某些东西以及完成块。

+ (void)requestAuthToken {

    NSLog(@"requestNewToken - Called: Requesting a new authorization bearer token.");

    //Indicate Network Activity
    [UIApplication sharedApplication].networkActivityIndicatorVisible = TRUE;

    [[NSURLCache sharedURLCache] removeAllCachedResponses];

    //Build request URL String
    NSString *requestString = [NSString stringWithFormat:@"%@%@",baseURL,authRequestURL];

    //Encode password so that it can be safely sent in request
    NSString *encodedPassword = [kU1Password stringByAddingPercentEncodingForRFC3986];

    //Populate post request with user credentials
    NSString *post = [NSString stringWithFormat:@"client_id=%@&password=%@&grant_type=%@", kU1ClientId, encodedPassword, kU1GrantType];

    //Encode post string & convert to type NSData
    NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];

    //Calculate the length of the post string
    NSString *postLength = [NSString stringWithFormat:@"%lu",(unsigned long)[postData length]];

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

    //Set the url for which you will pass your request data
    [request setURL:[NSURL URLWithString:requestString]];

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

    //Set HTTP header field with length of post data
    [request setValue:postLength forHTTPHeaderField:@"Content-Length"];

    //Set the encoded value for HTTP Header field
    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

    //Set the HTTP body of the urlrequest with our post data
    [request setHTTPBody:postData];

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

    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);

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

                                                        NSLog(@"requestAuthToken - Successful responce from server");

                                                        //Populate the auth object with the parse json data (handled entirely in the builder)
                                                        Token *auth = [TokenBuilder authFromJSON:data error:&error];
                                                        //Set the local tokens object equal to our responce object
                                                        //self.tokens = auth;

                                                        //Save the auth & refresh tokens in the keychain
                                                        [SAMKeychain setPassword:downloadedAuthToken forService:kServer account:kKeyAccessToken];
                                                        [SAMKeychain setPassword:downloadedRefreshToken forService:kServer account:kKeyRefreshToken];

                                                        //Get que and perform any UI changes
                                                        dispatch_async(dispatch_get_main_queue(), ^{
                                                            //_accessTokenLabel.text = _tokens.OOTAuthToken;
                                                            [UIApplication sharedApplication].networkActivityIndicatorVisible = FALSE;
                                                        });
                                                    }
                                                    else {
                                                        //Failed request
                                                        NSLog(@"requestAuthToken - error : %@", error.description);
                                                        dispatch_async(dispatch_get_main_queue(), ^{
                                                            [UIApplication sharedApplication].networkActivityIndicatorVisible = FALSE;
                                                        });
                                                    }
                                                }];
    [dataTask resume];
}

如果我尝试使函数 return 成为布尔值,我实际上无法 return 它在我的 Web 请求完成块中,因为它认为我是 return为请求设置一个值,而不是总体方法。

我还尝试使用委托通过请求的完成块传递布尔值,但布尔值立即执行(因为异步请求)并且基本上没有用。

我如何获取 + (void)requestAuthToken 并向其添加一个完成块,这样我就可以执行 [self refreshAuth withCompletionHandler:weakself.requestDataForUser]; 甚至

而不是调用 self requestAuthToken
[self requestAuthToken(^somethingblockyhere){
retry request
}];

谢谢

+animateWithDuration:animations: of UIView 是关于如何声明 void 块的简单示例。
它是这样声明的:

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations;

我个人从来不记得如何声明它们,我总是查看 iOS SDK(我知道一些方法)以记住声明它们的方式。

因此适用于您的问题:

+ (void)requestAuthToken:(void (^)(void))block
{
    //do your thing

    //When it's okay:
    if (block)
    {
        block();
    }
}

在你的另一个电话中(代码取自你的其他代码):

-(void)requestDataForUser
{
    //Do your things

    //Need to refresh token:
    [[CorrectClassName requestAuthToken:^{
        [weakSelf requestDataForUser];
    }];
}