使用ARC在其自己的完成块中引用NSOperation对象

时间:2012-02-10 05:15:22

标签: objective-c automatic-ref-counting objective-c-blocks grand-central-dispatch nsoperation

我很难将一些NSOperation代码转换为ARC。我的操作对象使用完成块,该完成块又包含一个GCD块,用于更新主线程上的UI。因为我从自己的完成块中引用了我的操作对象,所以我使用__weak指针来避免内存泄漏。但是,在我的代码运行时,指针已经设置为nil。

我已将其缩小到此代码示例。谁知道我哪里出错了,以及正确的方法来实现这个目标?

NSOperationSubclass *operation = [[NSOperationSubclass alloc] init];
__weak NSOperationSubclass *weakOperation = operation;

[operation setCompletionBlock:^{
    dispatch_async( dispatch_get_main_queue(), ^{

        // fails the check
        NSAssert( weakOperation != nil, @"pointer is nil" );

        ...
    });
}];

3 个答案:

答案 0 :(得分:16)

另一种选择是:

NSOperationSubclass *operation = [[NSOperationSubclass alloc] init];
__weak NSOperationSubclass *weakOperation = operation;

[operation setCompletionBlock:^{
    NSOperationSubclass *strongOperation = weakOperation;

    dispatch_async(dispatch_get_main_queue(), ^{
        assert(strongOperation != nil);
        ...
    });
}];

[operationQueue addOperation:operation];

我假设您还将操作对象添加到NSOperationQueue。在这种情况下,队列保留操作。它可能在执行完成块期间保留它(尽管我还没有找到关于完成块的官方确认)。

但是在完成块内部会创建另一个块。该块将在稍后的某个时间点运行,可能在NSOperations的完成块运行结束之后。发生这种情况时,队列将释放operationweakOperationniloperation。但是如果我们从操作的完成块创建另一个对同一对象的强引用,我们将确保在运行第二个块时存在operation,并避免保留周期,因为我们没有捕获{{1}}由块改变。

Apple在Transitioning to ARC Release Notes中提供此示例,请参阅使用终身限定符以避免强引用周期部分中的最后一个代码段。

答案 1 :(得分:10)

我不确定这一点,但正确的方法是将__block添加到有问题的变量中,然后在块的末尾将其设置为nil以确保它被释放。 See this question.

您的新代码如下所示:

NSOperationSubclass *operation = [[NSOperationSubclass alloc] init];
__block NSOperationSubclass *weakOperation = operation;

[operation setCompletionBlock:^{
    dispatch_async( dispatch_get_main_queue(), ^{

        // fails the check
        NSAssert( weakOperation != nil, @"pointer is nil" );

        ...
        weakOperation = nil;
    });

}];

答案 2 :(得分:4)

接受的答案是正确的。但是,从iOS 8 / Mac OS 10.10开始,无需弱化操作:

NSOperation documentation on @completionBlock的引用:

  

在iOS 8及更高版本和OS X v10.10及更高版本中,在完成块开始执行后,此属性设置为nil。

另见Pete Steinberger的this tweet