我一直在寻找一种方法来传递链式NSOperation
的结果。例如,假设我们有3个链接的操作:
Operation1
从服务器下载JSON
数据Operation2
解析&模型JSON收到Operation3
下载用户图片因此Op3将依赖于Op2,而Op2依赖于Op1。但我正在寻找从Op1传递结果的方法 - > Op2,然后来自Op2 - > Op3为:
[operation1 startWithURL:url];
[operation2 parseJSONfromOp1IntoModel:JSONData];
[operation3 downloadUserImagesForUser: UserModelObject];
和嵌套块似乎不是一个干净的可读解决方案,任何想法?
答案 0 :(得分:4)
如果要链接操作但不喜欢嵌套,可以使用NSOperation
子类,然后定义自己的完成处理程序:
DownloadOperation *downloadOperation = [[DownloadOperation alloc] initWithURL:url];
ParseOperation *parseOperation = [[ParseOperation alloc] init];
DownloadImagesOperation *downloadImagesOperation = [[DownloadImagesOperation alloc] init];
downloadOperation.downloadCompletionHandler = ^(NSData *data, NSError *error) {
if (error != nil) {
NSLog(@"%@", error);
return;
}
parseOperation.data = data;
[queue addOperation:parseOperation];
};
parseOperation.parseCompletionHandler = ^(NSDictionary *dictionary, NSError *error) {
if (error != nil) {
NSLog(@"%@", error);
return;
}
NSArray *images = ...;
downloadImagesOperation.images = images;
[queue addOperation:downloadImagesOperation];
};
[queue addOperation:downloadOperation];
坦率地说,我不确定这比嵌套方法更直观:
DownloadOperation *downloadOperation = [[DownloadOperation alloc] initWithURL:url downloadCompletionHandler:^(NSData *data, NSError *error) {
if (error != nil) {
NSLog(@"%@", error);
return;
}
ParseOperation *parseOperation = [[ParseOperation alloc] initWithURL:data parseCompletionHandler:^(NSDictionary *dictionary, NSError *error) {
if (error != nil) {
NSLog(@"%@", error);
return;
}
NSArray *images = ...
DownloadImagesOperation *downloadImagesOperation = [[DownloadImagesOperation alloc] initWithImages:images imageDownloadCompletionHandler:^(NSError *error) {
if (error != nil) {
NSLog(@"%@", error);
return;
}
// everything OK
}];
[queue addOperation:downloadImagesOperation];
}];
[queue addOperation:parseOperation];
}];
[queue addOperation:downloadOperation];
顺便说一句,上面假设您熟悉子类化NSOperation
,尤其是创建异步NSOperation
子类(以及执行所有必需的KVO)的细微之处。如果您需要如何完成的示例,请告诉我。
答案 1 :(得分:2)
创建链式操作:
从Op1的完成块内创建Op2,然后使用委托或类似的东西来设置对新创建的操作的依赖性。您可以使用此模式链接任意数量的链接。要在完成块中传递结果,您无法使用completionBlock
上的NSOperation
。你需要定义自己的(就像我对almostFinished
所做的那样)才能传递结果。
- (void)someMethod {
Operation1 *operation1 = [[Operation1 alloc] init];
operation1.almostFinished = ^(id op1Result) {
Operation2 *operation2 = [[Operation2 alloc] initWithResultFromOp1: op1Result];
operation2.almostFinished = ^(id op2Result) {
Operation3 *operation3 = [[Operation3 alloc] initWithResultFromOp2:op2Result];
operation3.completionBlock = ^{
NSLog(@"Operations 1 and 2 waited on me, but now we're all finished!!!);
};
[operation2 addDependency:operation3];
[queue addOperation:operation3];
};
[operation1 addDependency:operation2];
[queue addOperation:operation2];
};
[queue addOperation:operation1];
}
自定义子类
您需要将NSOperation
子类化才能实现此目的。正如我所提到的,您需要定义自己的完成块并确保在操作真正完成之前调用完成块,以便您可以添加依赖项。您可以将其添加到不同的块或委托方法中,而不是在新的完成块中添加依赖项。这样一来,我的例子简洁明了。
@interface Operation: NSOperation {
@property (nonatomic, copy) void (^almostFinished)(id result);
@end
@implementation Operation {
//...
- (void)main {
//...
// Call here to allow to add dependencies and new ops
self.almostFinished(result);
// Finish the op
[self willChangeValueForKey:@"isFinished"];
// repeat for isExecuting and do whatever else
[self didChangeValueForKey:@"isFinished"];
}
@end
编辑:这不是最易读的东西,但它包含一种方法中的所有代码。如果你想获得幻想,那就把事情放在委托方法中,或者用你如何定义这些东西来创造。