检查以下代码,并假设它是在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中如何做到这一点以及具体的语法是什么?
答案 0 :(得分:4)
作为一般情况,您可以自己参考。 E.g:
@implementation MasterOfMyOwnDestiny
{
MasterOfMyOwnDestiny *alsoMe;
}
- (void) lifeIsGood
{
alsoMe = self;
}
- (void) woeIsMe
{
alsoMe = nil;
}
...
@end
答案 1 :(得分:3)
以下是一些可能性:
NSOperationQueue
保留自己,直到它为空,然后自行释放。
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:
比这更复杂,因为它是线程安全的并且支持同时执行多个块。)
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。