链接完成块

时间:2012-12-11 23:40:05

标签: 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
}

虽然我认为这在技术上会起作用,但我并不为此而疯狂。感觉非常时髦。我希望有一个块封装第二个块,但这是不可能的,因为视图控制器和资源正在创建自己的完成块,而管理器类是必须将它们粉碎在一起的那个。

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

任何输入都会非常感激。

1 个答案:

答案 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.