2

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

-(无效)富{
    NSOperationQueue *oq = [[NSOperationQueue alloc] init];
    [oq addOperationWithBlock:^{
        // 假设我们在这里有一个长时间运行的操作。
    }];
}

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

这是如何实现的?

更新:

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

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

我做了很长一段时间的程序员,我很清楚这种事情的陷阱。我不希望被告知这是一个好主意还是坏主意。我认为总的来说这是一个坏的。相反,我的问题是学术性的:无论这是一个好主意还是坏主意,如何在 ARC 中做到这一点,这样做的具体语法是什么?

4

4 回答 4

4

作为一般情况,您可以保留对自己的引用。例如:

@implementation MasterOfMyOwnDestiny
{
   MasterOfMyOwnDestiny *alsoMe;
}

- (void) lifeIsGood
{
    alsoMe = self;
}

- (void) woeIsMe
{
    alsoMe = nil;
}

...

@end
于 2012-05-08T00:15:00.917 回答
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. (realaddOperationWithBlock:比这更复杂,因为它是线程安全的并且支持同时执行多个块。)

  3. NSOperationQueue 不会超出您的foo方法的范围。也许到addOperationWithBlock:返回时,您的长时间运行的块已经提交到 GCD 队列。由于您没有强烈引用oq,因此没有理由oq 应该释放。

于 2012-05-07T22:42:30.930 回答
0

在给出的示例代码中,在 ARC 下,在块的封闭词法范围内本地的 NSOperationQueue 被块捕获。基本上,块保存指针的值,以便以后可以从块内访问它。无论您是否使用 ARC,这实际上都会发生;不同的是,在 ARC 下,对象变量会随着块的复制和释放而自动保留和释放。

块编程主题指南中的“对象和块变量”部分是这方面的一个很好的参考。

于 2012-05-08T00:38:02.767 回答
0

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

于 2012-05-08T04:57:01.810 回答