Chaining `NSOperation` : 将一个操作的结果传递给下一个操作
Chaining `NSOperation` : Pass result from an operation to the next one
我一直在寻找一种方法来传递链式 NSOperation
的结果。例如,假设我们有 3 个链接的操作:
Operation1
从服务器下载 JSON
数据
Operation2
解析和建模 JSON 收到
Operation3
下载用户图片
所以 Op3 将依赖于 Op2,而 Op2 又依赖于 Op1。但我正在寻找从 Op1 -> Op2,然后从 Op2 -> Op3 传递结果的方法:
[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)的微妙之处。如果您需要有关如何完成的示例,请告诉我。
我一直在寻找一种方法来传递链式 NSOperation
的结果。例如,假设我们有 3 个链接的操作:
Operation1
从服务器下载JSON
数据Operation2
解析和建模 JSON 收到Operation3
下载用户图片
所以 Op3 将依赖于 Op2,而 Op2 又依赖于 Op1。但我正在寻找从 Op1 -> Op2,然后从 Op2 -> Op3 传递结果的方法:
[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)的微妙之处。如果您需要有关如何完成的示例,请告诉我。