我有两个不同类的实例,他们都需要为特定操作添加一个完成块。我会尝试一般性地解释这个问题,而不是解释我的应用程序试图做的所有事情。
视图控制器正在调用资源管理器类的实例,以便保存资源。然后,资源管理器调用要保存的资源类,以获取保存的网络操作。
资源实例创建操作并为其提供一个完成块,该块将在触发时影响资源的状态。
这就是我的问题所在 - 资源类还需要为此操作添加一个完成块,以便视图控制器被告知保存成功或失败。
以下是经理上保存方法的信息:
-(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
}
虽然我认为这在技术上会起作用,但我并不为此而疯狂。感觉非常时髦。我希望有一个块封装第二个块,但这是不可能的,因为视图控制器和资源正在创建自己的完成块,而管理器类是必须将它们粉碎在一起的那个。
在这种情况下,是否有更优雅的方法将这两个完成块链接在一起,或者我现在的方法是创建一个块来包含原来的两个块,我将获得最好的块?
任何输入都会非常感激。
答案 0 :(得分:2)
您发布的代码可能不工作。当您使用自己的块替换操作的完成块时,您可能正在删除对原始完成块(由资源设置)的唯一强引用。因此,resourceCompletion
变量弱,在setCompletionBlock:
返回时将变为零。
只需使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
的班级,因为Apple reserves the NS
prefix (and all other two-letter prefixes) for its own use.