链式完井块

  • 本文关键字:完井 objective-c ios
  • 更新时间 :
  • 英文 :


我有两个不同类的实例,它们都需要向特定操作添加一个完成块。我会尝试一般性地解释这个问题,而不是解释我的应用程序试图做的一切

视图控制器正在调用资源管理器类的实例以保存资源。然后,资源管理器调用要保存的资源的类,以获取保存的网络操作。

资源的实例创建操作并为其提供一个完成块,该块将在资源激发时影响资源的状态。

这就是我的问题所在——资源类还需要向该操作添加一个完成块,以便向视图控制器通知保存的成功或失败。

这里有一个关于经理保存方法的小技巧:

-(void)save:resource withCompletion:completion
{
.
.
.
NSOperation *operation = [resource operationForSave];
NSOperation __weak *weakOperation = operation;
void(^__weak resourceCompletion)(void)= operation.completionBlock;
[operation setCompletionBlock:^{
if (resourceCompletion) {
resourceCompletion();
}
if (completion) {
if (weakOperation.error) {
completion(NO, operation.error);
}
else {
completion(YES, nil);
}
}
}];
.
.
.
// add the operation to a network operation queue
}

虽然我认为这在技术上是可行的,但我并不疯狂。它感觉很时髦。我更喜欢用一个块封装第二个块,但这是不可能的,因为视图控制器和资源正在创建自己的完成块,而管理器类必须将它们分解在一起。

在这种情况下,有没有更优雅的方法将这两个完成块链接在一起,或者我目前创建一个包含原始两个块的块的方法是最好的?

如有任何意见,我们将不胜感激。

您发布的代码可能不起作用。当您将操作的完成块替换为自己的块时,可能会删除对原始完成块(由资源设置)的唯一强引用。因此,当setCompletionBlock:返回时,弱的resourceCompletion变量将变为零。

只要使resourceCompletion强大就可以解决问题。但是,如果您想以更干净的方式进行操作,请修改(资源上的)operationForSave消息,使其本身具有一个完成块:

__block NSNetworkOperation *operation = [resource operationForSaveWithCompletion:^{
NSError *error = operation.error;
completion(error == nil, error);
// Break the retain cycle between this block and the operation object.
operation = nil;
}];

并将调用您提供的完成块作为资源自己的内部完成块的工作。

如果你不想或不能修改资源的API,你仍然可以通过消除弱引用来简化你的代码:

__block NSNetworkOperation *operation = [resource operationForSave];
__block void (^priorCompletion)(void) = operation.completionBlock;
operation.completionBlock = ^{
if (priorCompletion) {
priorCompletion);
// Break possible retain cycle.
priorCompletion = nil;
}
NSError *error = operation.error;
completion(error == nil, error);
// Break the retain cycle between this block and the operation object.
operation = nil;
};

此外,我真诚地希望你不要真的有一个名为NSNetworkOperation的类,因为苹果保留了NS前缀(以及所有其他两个字母的前缀)供自己使用。