为两个连续的HTTP GET嵌套NSURLSessionDataTask



我是Objective C的初学者,我希望完成两个连续的HTTPGET(一个接一个)。到目前为止,我在第一个NSURLSessionDataTask的完成块中有一个NSURLSessionDataTask。这导致我的代码有点不可读,所以我想知道有什么更好的方法可以做到这一点?以下是一些示例代码:

{
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];    
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
    NSMutableURLRequest *url_request_1 = [NSMutableURLRequest requestWithURL:@"some_url_1"];
    [url_request_1 setHTTPMethod:@"GET"];
    NSURLSessionDataTask *url_task_1 = [session
        dataTaskWithRequest:url_request_1
        completionHandler:^(NSData *data1,
        NSURLResponse *response1,
        NSError *error1) {
            if(data1 !=nil){
                // Evaluate some_url_2 from the response of url_task_1
                NSMutableURLRequest *url_request_2 = [NSMutableURLRequest requestWithURL:@"some_url_2"];
                [url_request_2 setHTTPMethod:@"GET"];
                NSURLSessionDataTask *url_task_2 = [session
                     dataTaskWithRequest:url_request_2
                     completionHandler:^(NSData *data2,
                     NSURLResponse *response2,
                     NSError *error2) {
                        if(data2 !=nil){      
                            // Process data here                 
                        } else {
                            // Handle error here.
                            return;
                        }
                    }];
                [urlRequest2 resume];
            }
            else{
                // Handle error here
                return;
            }
        }];
    [url_task_1 resume];
}

通过更改缩进样式和使用早期退出模式,这就不那么麻烦了。

- (void)performRequestsWithCompletion:(void (^ _Nonnull)(NSDictionary *, NSError *))completion {
    NSMutableURLRequest *request1 = [NSMutableURLRequest requestWithURL:firstURL];
    NSURLSessionDataTask *task1 = [self.session dataTaskWithRequest:request1 completionHandler:^(NSData *data1, NSURLResponse *response1, NSError *error1) {
        if (!data1) {
            // handle error here, then return
            completion(nil, error1);
            return;
        }
        NSMutableURLRequest *request2 = [NSMutableURLRequest requestWithURL:secondURL];
        NSURLSessionDataTask *task2 = [self.session dataTaskWithRequest:request2 completionHandler:^(NSData *data2, NSURLResponse *response2, NSError *error2) {
            if (!data2) {
                // handle error here, then return
                completion(nil, error2);
                return;
            }
            // handle parsing `data2` here
            NSDictionary *result = ...;
            completion(result, nil);
        }];
        [task2 resume];
    }];
    [task1 resume];
}

注意,我在这里添加了一个完成处理程序,因为这是最好的模式之一,可以让任何启动此请求的东西都完成。很明显,我的块参数假设您将返回一个字典,所以您应该将其更改为例程返回的任何类型。

或者(尤其是如果你要做的不仅仅是两个连续的web服务调用),你可以将其分解为不同的方法:

- (void)performRequestsWithCompletion:(void (^ _Nonnull)(NSDictionary *, NSError *))completion {
    [self performFirstRequestWithCompletion:completion];
}
- (NSURLSessionTask *)performFirstRequestWithCompletion:(void (^ _Nonnull)(NSDictionary *, NSError *))completion {
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:firstURL];
    NSURLSessionTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (!data || error) {
            // Handle error here
            completion(nil, error);
            return;
        }
        // Evaluate some_url_2 from the response of url_task_1
        [self performSecondRequestWithCompletion:completion];
    }];
    [task resume];
    return task;
}
- (NSURLSessionTask *)performSecondRequestWithCompletion:(void (^ _Nonnull)(NSDictionary *, NSError *))completion {
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:secondURL];
    NSURLSessionTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (!data || error) {
            // Handle error here, and return
            completion(nil, error);
            return;
        }
        // Process data here
        NSDictionary *result = ...;
        completion(result, nil);
    }];
    [task resume];
    return task;
}

使用这种模式,无论您有多少依赖调用,都不会得到嵌套块的塔。


出于完整性的考虑,避免块中这些块塔的其他模式包括NSOperation模式和第三方方法,如期货/承诺(例如PromiseKit)。这些都超出了这个问题的范围,但如果你经常这样做,它们值得考虑。

最新更新