ARC是否处理这种情况而不泄漏?如果是这样,怎么样?

时间:2013-01-20 22:15:11

标签: objective-c cocoa

ARC似乎非常好,但是有一两个边缘情况,典型的命名约定/规则对我来说并不清楚。查看NSThread周围的以下类别实现:

@interface NSThread (BlockAdditions)
- (void)performBlock:(dispatch_block_t)block;
@end

@implementation NSThread (BlockAdditions)
- (void)internal_performBlock:(dispatch_block_t)block
{
    block();
}

- (void)performBlock:(dispatch_block_t)block
{
    [self performSelector:@selector(internal_performBlock:)
                 onThread:self
               withObject:[block copy]
            waitUntilDone:NO];
}

我的问题是:调用block-copy是否泄漏?编译器如何知道何时释放块?仪器没有检测到泄漏,但鉴于我对ARC的了解,这并不能说服我这个案例得到正确处理。感谢您的任何信息!

2 个答案:

答案 0 :(得分:5)

这会在保留/释放中泄漏,但不应在ARC中泄漏。

编译器看到-copy,这意味着需要-release。如果你看一下生成的程序集,那应该就是你所看到的。

(嗯,正如你在整个装配过程中所看到的那样,这不是很简单。)

请注意,您只需编译[block copy];即可简化程序集。

答案 1 :(得分:1)

编译器发现block已复制到方法performBlock:中。这会在方法中创建一个新对象,并且必须在方法返回之前释放方法中创建的每个对象,除非返回此对象,在这种情况下必须自动释放,因为一旦方法返回,编译器就不会引用变量在方法中任何时候都不会释放它。

所以你的方法大致翻译为

- (void)performBlock:(dispatch_block_t)block
{
    dispatch_block_t blockCopy;

    blockCopy = [block copy];
    [self performSelector:@selector(internal_performBlock:)
                 onThread:self
               withObject:blockCopy
            waitUntilDone:NO];

    // If method returns, how shall the compiler access blockCopy any longer?
    // It can't! And since blockCopy is not returned by the method, it must
    // be destroyed before the method returns.
    [blockCopy release];
}

您可能想知道,为什么此代码不会崩溃,不会blockCopy被解除分配?不,因为performSelector:onThread:withObject:waitUntilDone:保留了作为withObject:参数传递给它的对象,直到它执行选择器回调,之后它再次释放对象。因此,当在release结束时调用performBlock:时,blockCopy的{​​{1}}为2,此版本将其降低为1,但不会降为0,因此不会释放。只有在另一个线程上调用了选择器之后,才会再次释放retainCount,并且由于被调用的选择器没有保留它,它最终将被解除分配。