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