Ios 链接“NSOperation”:将一个操作的结果传递到下一个操作
我一直在寻找一种方法来传递链式Ios 链接“NSOperation”:将一个操作的结果传递到下一个操作,ios,objective-c,nsoperation,nsoperationqueue,Ios,Objective C,Nsoperation,Nsoperationqueue,我一直在寻找一种方法来传递链式NSOperation的结果。例如,假设我们有3个链接的操作: Operation1从服务器下载JSON数据 Operation2解析和建模接收到的JSON 操作3下载用户图像 所以Op3依赖于Op2,而Op2依赖于Op1。但我正在寻找从Op1->Op2传递结果的方法,然后从Op2->Op3传递结果为: [operation1 startWithURL:url]; [operation2 parseJSONfromOp1IntoModel:JSONData]; [o
NSOperation
的结果。例如,假设我们有3个链接的操作:
Operation1
从服务器下载JSON
数据Operation2
解析和建模接收到的JSON操作3
下载用户图像[operation1 startWithURL:url];
[operation2 parseJSONfromOp1IntoModel:JSONData];
[operation3 downloadUserImagesForUser: UserModelObject];
嵌套块似乎不是一个清晰易读的解决方案,你知道吗?创建链式操作: 从Op1的完成块中创建Op2,然后使用委托或类似的方法来设置对新创建的操作的依赖关系。您可以使用此模式链接任意数量的对象。要在完成块中传递结果,不能使用
NSOperation
上的completionBlock
。您需要定义自己的(就像我在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
编辑:这不是最可读的东西,但它包含一个方法中的所有代码。如果你想变得有趣,那么就把事情放在委托方法中,或者创造性地定义这些事情。如果你想链接操作,但不喜欢嵌套,你可以使用
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)的微妙之处。如果你需要这方面的例子,请告诉我 您是否尝试过使用completionBlock
?您是否看到我找到了一个用于执行这种排序的有用库。遗憾的是,使用自定义完成处理程序嵌套块是典型的NSOperation
方法。或者看看承诺/未来,例如或。@Rob,谢谢,但出于某些原因,我必须坚持使用SDK而不是第三方库,否则我会用不到8行代码来完成:)谢谢@keithbhunter,我现在尝试子类化。我想说第一种方法看起来正确,但有一个小错误。配置每个操作后,应设置依赖项,然后将所有3个操作添加到队列中,而不是在每个操作结束后。如果返回任何错误,则取消队列。是的,这是另一种模式。我故意省略了它,因为它有点易碎。当您有操作依赖项时,这不一定应用它们的完成处理程序,它们可以在不同的线程上异步运行。因此,如果要在完成处理程序中传递数据,则在操作完成之前,NSOperation
子类必须同步调用其完成处理程序。但是,让代码完整性取决于另一个类的实现细节是值得怀疑的设计。上述选项完全依赖于更健壮的公共接口。