我正在尝试在 ObjectC 中编写一个函数,该函数返回一个具有 3 个属性的类。对于程序必须从远程服务器获取的每个属性(AFNetworking),我想知道这个问题的好解决方案是什么?这是我正在编写的函数的当前结构
- (MyClass *)fillInClassAndReturn {
MyClass *myClass = [MyClass new];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:@"Url1"
parameters:parameter1
success:^(AFHTTPRequestOperation *operation, id responseObject) {
myClass.property1 = responseObject;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
myClass.property1 = nil;
}];
[manager GET:@"Url2"
parameters:parameter2
success:^(AFHTTPRequestOperation *operation, id responseObject) {
myClass.property2 = responseObject;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
myClass.property2 = nil;
}];
[manager GET:@"Url13"
parameters:parameter3
success:^(AFHTTPRequestOperation *operation, id responseObject) {
myClass.property3 = responseObject;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
myClass.property3 = nil;
}];
return myClass;
}
此函数将在调用此函数后立即返回myClass
,此时将nil
所有三个属性,当从服务器获取相应的数据时,将填充它。因此,使用此函数的人必须为函数的返回值定义 KVO,并在值更改时收到通知。但是这是这个设计的一个问题,如果返回的值是NSArray/NSMutableArray
而不是MyClass
,它将不起作用那么有没有更好的设计,这样我就可以处理这种情况?如果这个设计没有那么可怕,如何处理NSArray*
的情况?
几个观察结果:
-
由于这是一个异步运行的方法,因此您不希望尝试立即返回任何内容,而是使用完成块模式,即在三个请求完成时将调用的
completionHandler
。 -
由于您有三个同时运行的请求,因此您需要某种方法来了解所有三个请求何时完成。由于使用的是基于
NSOperation
的解决方案 (AFHTTPRequestOperation
),因此可以使用操作依赖项。
无论如何,这会产生如下结果:
- (void)fillInClassWithCompletion:(void (^)(MyClass *myClass))completionHandler {
MyClass *myClass = [MyClass new];
NSBlockOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
if (completionHandler) {
completionHandler(myClass);
}
}];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSOperation *operation1 = [manager GET:@"Url1" parameters:parameter1 success:^(AFHTTPRequestOperation *operation, id responseObject) {
myClass.property1 = responseObject;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
myClass.property1 = nil;
}];
[completionOperation addDependency:operation1];
NSOperation *operation2 = [manager GET:@"Url2" parameters:parameter2 success:^(AFHTTPRequestOperation *operation, id responseObject) {
myClass.property2 = responseObject;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
myClass.property2 = nil;
}];
[completionOperation addDependency:operation2];
NSOperation *operation3 = [manager GET:@"Url13" parameters:parameter3 success:^(AFHTTPRequestOperation *operation, id responseObject) {
myClass.property3 = responseObject;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
myClass.property3 = nil;
}];
[completionOperation addDependency:operation3];
[[NSOperationQueue mainQueue] addOperation:completionOperation];
}
这可能是最合乎逻辑的方法。从技术上讲,如果将AFHTTPRequestOperationManager
的completionQueue
更改为并发队列,则上述内容引入了可能的争用条件,因此您可以使用调度组机制来了解是否完成了所有三个:
- (void)fillInClassWithCompletion:(void (^)(MyClass *myClass))completionHandler {
MyClass *myClass = [MyClass new];
dispatch_group_t group = dispatch_group_create();
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
dispatch_group_enter(group);
[manager GET:@"Url1" parameters:parameter1 success:^(AFHTTPRequestOperation *operation, id responseObject) {
myClass.property1 = responseObject;
dispatch_group_leave(group);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
myClass.property1 = nil;
dispatch_group_leave(group);
}];
dispatch_group_enter(group);
[manager GET:@"Url2" parameters:parameter2 success:^(AFHTTPRequestOperation *operation, id responseObject) {
myClass.property2 = responseObject;
dispatch_group_leave(group);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
myClass.property2 = nil;
dispatch_group_leave(group);
}];
dispatch_group_enter(group);
[manager GET:@"Url13" parameters:parameter3 success:^(AFHTTPRequestOperation *operation, id responseObject) {
myClass.property3 = responseObject;
dispatch_group_leave(group);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
myClass.property3 = nil;
dispatch_group_leave(group);
}];
dispatch_group_notify(group, manager.completionQueue ?: dispatch_get_main_queue(), ^{
if (completionHandler) {
completionHandler(myClass);
}
});
}
无论哪种方式,您使用它的方式都是:
[object fillInClassWithCompletion:^(MyClass *myClass) {
// use myClass here
}];
您可能还希望扩展此completionHandler
以传回错误对象,因为这是常见做法,如果调用方希望根据错误的性质自定义其错误处理,则此方法很有用,但我会将其留给您。