链接`NSOperation`:将操作的结果传递给下一个

我一直在寻找一种方法来传递链接NSOperation结果。 例如,假设我们有3个操作链接:

  1. Operation1从服务器下载JSON数据
  2. Operation2来parsing和模型接收的JSON
  3. Operation3下载用户图像

所以Op3将依赖于Op2,Op2依赖于Op1。 但是我正在寻找将Op1 – > Op2,Op2 – > Op3的结果传递给下面的方法:

 [operation1 startWithURL:url]; [operation2 parseJSONfromOp1IntoModel:JSONData]; [operation3 downloadUserImagesForUser: UserModelObject]; 

和嵌套块似乎不是一个干净的可读解决scheme,任何想法?

如果你想连锁操作,但不喜欢嵌套,你可以使用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子类,尤其是创build一个asynchronousNSOperation子类(以及完成所有必要的KVO)的细微之处。 如果你需要这样做的例子,让我知道。

创build链式操作:

从Op1的完成块中创buildOp2,然后使用委托或类似的方式设置对新创build的操作的依赖关系。 你可以使用这个模式连锁尽可能多的。 要在完成块中传递结果,不能使用NSOperation上的NSOperation 。 你需要定义你自己的(就像我对almostFinished所做的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 

编辑:这不是最可读的东西,但它包含一个方法中的所有代码。 如果你想变得有趣,那就把事情放在委托方法中,或者如何定义这些东西来创造性。