2

在以前版本的 AFNetworking 上,我可以利用它AFHTTPRequestOperation来创建多个请求,在它们之间创建依赖关系并将它们排入队列。示例(AFHTTPClient子类内部):

NSURLRequest *categoriesRequest = [self requestWithMethod:@"GET" path:@"categories" parameters:nil];
AFHTTPRequestOperation *categoriesOperation = [self HTTPRequestOperationWithRequest:categoriesRequest success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSArray *jsonCategories = responseObject;
    for (NSDictionary *jsonCategory in jsonCategories) {
        SPOCategory *category = [[SPOCategory alloc] initWithDictionary:jsonCategory];
        [self.categories addObject:category];
    }
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    // …
}];

NSURLRequest *incidencesRequest = [self requestWithMethod:@"GET" path:@"incidences" parameters:nil];
AFHTTPRequestOperation *incidencesOperation = [self HTTPRequestOperationWithRequest:incidencesRequest success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSArray *jsonIncidences = responseObject;
    for (NSDictionary *jsonIncidence in jsonIncidences) {
        SPOIncidence *incidence = [[SPOIncidence alloc] initWithDictionary:jsonIncidence];
        [self.incidences addObject:incidence];
    }

    completionBlock(self.incidences, self.categories, nil);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    // …
}];

[incidencesOperation addDependency:categoriesOperation];

[self enqueueBatchOfHTTPRequestOperations:@[categoriesOperation, incidencesOperation] progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
    // Processing…
} completionBlock:^(NSArray *operations) {
    // Completed
}];

我知道我可以继续使用,AFHTTPRequestOperation但是,我想知道是否有类似的方法可以在 的子类中实现相同的事情AFHTTPSessionManager,使用NSURLSession作为后备库而不是NSURLConnection.

谢谢!

4

1 回答 1

2

AFHTTPSessionManager的连接工厂方法创建将由NSURLSessionDataTask对象表示的连接。

AFHTTPRequestOperation这些不同的是,它们不是NSOperation子类,因此不可能声明依赖关系。

可以想象包装一个工厂方法,如

- (NSURLSessionDataTask *)GET:(NSString *)URLString
                   parameters:(NSDictionary *)parameters
                      success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
                      failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure;

NSOperation进入返回对象的辅助方法/函数。不过,这可能(将会)变得很麻烦并且看起来很奇怪。

如果您有足够的勇气考虑另一个第三方库,您可以按照以下说明解决您的问题:

这个想法是通过“承诺”来表示异步操作的最终结果。将 Promise 视为结果的占位符,最终将由操作设置。所以,基本上你将一个工厂方法包装成一个,然后有效地产生一个具有这个签名的方法:

-(Promise*) fetchCategories;

或者

-(Promise*) fetchCategoriesWithParameters:(NSDictionary*)parameters;

请注意,上述方法是异步的——但它们没有完成处理程序。Promise 将改为提供此功能。

最初,当fetchCategories返回时,promise 对象不“包含”结果。

通过“注册”一个完成处理程序块 和一个具有如下属性的错误处理程序块(伪代码),您分别获得(在稍后的某个时间)最终结果和错误:then

  [self.fetchCategoriesWithParameters].then( 
      <success handler block>, 
      <failure handler block> ); 

更完整的代码片段:

Promise* categoriesPromise = [self fetchCategories];

categoriesPromise.then(^id(id result){
    self.categories = result;
    ... // (e.g, dispatch on main thread and reload table view)
    return nil;
}, ^id(NSError* error){
    NSLog(@"Error: %@", error);
    return nil;
});

注意:成功处理程序块的参数结果是操作的最终结果,也就是responseObject

现在,为了“链接”多个异步操作(包括处理程序),您可以这样做:

self.categoriesPromise = [self fetchCategories];

Promise* finalResult = self.categoriesPromise.then(^id(id result){
    NSArray *jsonCategories = result;
    for (NSDictionary *jsonCategory in jsonCategories) {
        SPOCategory *category = [[SPOCategory alloc] initWithDictionary:jsonCategory];
        [self.categories addObject:category];
    }
   return [self fetchIncidencesWithParams:result);
}, nil)
.then(^id(id result){
    NSArray *jsonIncidences = result;
    for (NSDictionary *jsonIncidence in jsonIncidences) {
        SPOIncidence *incidence = 
          [[SPOIncidence alloc] initWithDictionary:jsonIncidence];
        [self.incidences addObject:incidence];
    }
    return @[self.incidences, self.categories];
}, nil)
.then(^id(id result){
    NSArray* incidences = result[0];
    NSArray* categories = result[1];
    ...
    return nil;
}, nil /* error handler block */);

您创建并“解决”(即设置结果)一个 Promise,如下所示:

- (Promise*) fetchCategories {
    Promise* promise = [[Promise alloc] init];

    NSURLRequest *categoriesRequest = [self requestWithMethod:@"GET" path:@"categories" parameters:nil];
    AFHTTPRequestOperation *categoriesOperation = [self  HTTPRequestOperationWithRequest:categoriesRequest success:^(AFHTTPRequestOperation *operation, id responseObject) {
        [promise fulfillWithResult:responseObject];
    }
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        [promise rejectWithReason:error];
    }];

    return promise;
}

免责声明:

有一些第三方 Objective-C 库以这种或类似的方式实现 Promise。我是RXPromise的作者,它根据Promises/A+规范实现了一个承诺。

于 2013-10-16T16:20:58.683 回答