2

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

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

资源的实例创建操作并给它一个完成块,该块将在它触发时影响资源的状态。

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

这是管理器上保存方法的片段:

-(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
}

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

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

任何输入将不胜感激。

4

1 回答 1

2

您发布的代码可能无法正常工作。当您用自己的块替换操作的完成块时,您可能正在删除对原始完成块(由资源设置)的唯一强引用。因此,您的resourceCompletion变量很弱,到时间setCompletionBlock:返回时将变为 nil。

只是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 保留NS前缀(以及所有其他两个字母前缀)供自己使用。

于 2012-12-11T23:59:36.310 回答