ARC的手动对象寿命

时间:2012-05-07 22:27:37

标签: objective-c automatic-ref-counting

检查以下代码,并假设它是在ARC下编译的:

- (void)foo {
    NSOperationQueue *oq = [[NSOperationQueue alloc] init];
    [oq addOperationWithBlock:^{
        // Pretend that we have a long-running operation here.
    }];
}

虽然操作队列被声明为局部变量,但只要它具有运行操作,它的生命周期就会超出方法的范围。

这是如何实现的?

更新

我很欣赏Rob Mayoff经过深思熟虑的评论,但我认为我没有正确地提出我的问题。我没有问一个关于NSOperationQueue的具体问题,而是关于ARC中对象生存期的一般性问题。具体来说,我的问题是:

在ARC下,一个对象如何参与其自身生命周期的管理?

我很长一段时间都是程序员,我很清楚这种事情的陷阱。我不打算讲这是好还是坏。我认为一般来说这是一个糟糕的。相反,我的问题是学术性的:无论是好还是坏,在ARC中如何做到这一点以及具体的语法是什么?

4 个答案:

答案 0 :(得分:4)

作为一般情况,您可以自己参考。 E.g:

@implementation MasterOfMyOwnDestiny
{
   MasterOfMyOwnDestiny *alsoMe;
}

- (void) lifeIsGood
{
    alsoMe = self;
}

- (void) woeIsMe
{
    alsoMe = nil;
}

...

@end

答案 1 :(得分:3)

以下是一些可能性:

  1. NSOperationQueue保留自己,直到它为空,然后自行释放。

  2. NSOperationQueue会导致其他一些对象保留它。例如,由于NSOperationQueue使用GCD,因此addOperationWithBlock:看起来像这样:

    - (void)addOperationWithBlock:(void (^)(void))block {
        void (^wrapperBlock)(void) = ^{
            block();
            [self executeNextBlock];
        };
        if (self.isCurrentlyExecuting) {
            [self.queuedBlocks addObject:wrapperBlock];
        } else {
            self.isCurrentlyExecuting = YES;
            dispatch_async(self.dispatchQueue, wrapperBlock);
        }
    }
    

    在该代码中,wrapperBlock包含对NSOperationQueue的强引用,因此(假设为ARC),它保留NSOperationQueue。 (真正的addOperationWithBlock:比这更复杂,因为它是线程安全的并且支持同时执行多个块。)

  3. NSOperationQueue 不会超出foo方法的范围。也许在addOperationWithBlock:返回时,您的长时间运行块已经提交到GCD队列。由于您没有对oq进行强有力的引用,因此没有理由{/ 1}} 不应取消分配。

答案 2 :(得分:0)

在示例代码中,在ARC下,块捕获捕获的NSOperationQueue,它是块的封闭词法范围的本地。基本上,该块保存指针的值,以便稍后可以在块内访问它。无论你是否使用ARC,这实际上都会发生;区别在于,在ARC下,对象变量会在复制和释放块时自动保留和释放。

"Object and Block Variables"指南中的Blocks Programming Topics部分是这个内容的一个很好的参考。

答案 3 :(得分:0)

我能想到的最简单的事情就是拥有一个全局的NSMutableArray(或set,或者其他),该对象将自己添加到自身并从中移除。另一个想法是将(如你已经承认的)奇怪的内存管理代码放在非ARC文件的类别中,并直接使用-retain和-release。