带有完成和参数的块

Block with completion and arguments

我是积木新手。我正在尝试分析以下代码的工作原理。

据我了解,此特定方法有一个块并且 returns a

NSURLSessionDataTask

getTotalFollowersFrom 是方法的名称。 (NSString*)influencerId 是调用此方法时传递的userId。使用 WithCompletion: 以便我们知道该方法何时完成 Api 调用。 Void是什么块returns。插入符号 (^) 用于定义块。以下(id _Nullable likesCountRequestResponse, NSError * _Nullable error)completion为参数。这是我不明白的。根据文档 arguments 在块内有 return 值。我看到 return 是 NSURLSessionDataTaskreturn result;,但我不明白块参数的值 return 是如何产生的。我错过了什么?谁能给我解释一下吗?

- (NSURLSessionDataTask *)getTotalLikesFrom:(NSString*)userId withCompletion:(void (^)(id _Nullable likesCountRequestResponse, NSError * _Nullable error))completion {
    
    NSString* postString = [NSString stringWithFormat:@"apicall/%@", userId];
    
    @weakify(self)
    NSURLSessionDataTask *result = [self GET:postString parameters:nil completion:^(OVCResponse * _Nullable response, NSError * _Nullable error) {
        
        @strongify(self)
        [self handleResponse:response error:error adjustErrorBlock:self.commonValidationErrorAdjustBlock completion:completion];
        
    }];
    
    return result;
}

- (void)handleResponse:(nullable OVCResponse *)response error:(nullable NSError *)error adjustErrorBlock:(nullable ApiClientv2AdjustErrorBlock)adjustErrorBlock completion:(void (^)(id _Nullable result, NSError * _Nullable error))completion 
{ 
if (response.HTTPResponse.statusCode >= 500) 
{
error = nil != error ? error : NSError.com_eight_APIServiceUnknownError; [SentrySDK captureError:error];
}
else 
{
error = nil != error ? error : NSError.com_eight_APIServiceUnknownError;
}
id result = nil == error ? response.result : nil;
completion(result, error);
} 

您的示例不完整。所以,让我们考虑一个 MCVE:

- (NSURLSessionDataTask *)networkRequestWithCompletion:(void (^)(NSDictionary * _Nullable object, NSError * _Nullable error))completion {
    NSURL *url = [NSURL URLWithString:@"https://httpbin.org/get"];

    NSURLSessionDataTask *task = [NSURLSession.sharedSession dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (!data || error) {
            completion(nil, error);
            return;
        }

        NSError *parseError;
        NSDictionary *resultObject = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&parseError];
        if (parseError) {
            completion(nil, parseError);
            return;
        }

        completion(resultObject, nil);
    }];

    [task resume];

    return task;
}

这执行网络请求并解析 JSON。在该方法中,您将看到对以下内容的引用:

completion(nil, error);

或:

completion(resultObject, nil);

数据就是这样传回给调用者的。该方法在调用 completion 时提供块的参数。因此,可以为该方法提供一个块并使用这两个参数:

[self networkRequestWithCompletion:^(NSDictionary *dictionary, NSError *error) {
    if (error) {
        NSLog(@"error = %@", error);
        return;
    }

    // you can access the `dictionary` parameter here ...

    NSLog(@"dictionary = %@", dictionary);
}];

// ... but you cannot reference the `dictionary` or `error` parameters here
// because the above runs asynchronously (i.e., later).

在您在问题中提供的代码片段中,您没有在任何地方调用 completion。但请注意,它提供给 handleResponse。那个方法无疑是在给你打卡


作为个人喜好问题,我认为 resultNSURLSessionDataTask 的选择有点混乱。所以在我的例子中,我给它取了一个更好的名字,task,以明确它是NSURLSessionTask对象,而不是网络请求的结果

但是这个对象的用途是什么?这样调用者就可以选择取消请求。例如,您可能有:

@interface ViewController ()
@property (nonatomic, weak) NSURLSessionTask *task;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.task = [self networkRequestWithCompletion:^(NSDictionary *dictionary, NSError *error) {
        if (error) {
            NSLog(@"error = %@", error);
            return;
        }

        NSLog(@"dictionary = %@", dictionary);
    }];
}

- (IBAction)didTapCancelButton:(id)sender {
    [self.task cancel];
}

...

@end

所以,NSURLSessionTask 引用被返回,我们保存它,这样我们就可以有一个取消按钮,例如,将取消该异步网络请求。

但是,简而言之,不要将 networkRequestWithCompletion 立即返回的 NSURLSessionTask 引用(让我们可以选择稍后取消请求)与块的参数混为一谈,这我们用来向调用者提供网络请求的结果。