1

我是 Objective C 的初学者,我希望做两个连续的 HTTP GET(一个接一个)。到目前为止,我在第一个 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];
}
4

1 回答 1

1

通过更改缩进样式和使用提前退出模式,这会变得不那么笨拙。

- (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)。这些超出了这个问题的范围,但如果你经常这样做,它们值得考虑。

于 2015-11-29T18:26:31.760 回答