2013-01-20 50 views
4

ARC看起来很不错,但有一个或两个边缘的情况下,典型的命名惯例/规则不明确地告诉我。看看周围NSThread以下类别执行:ARC是否处理这种情况而不泄漏?如果是这样,怎么样?

@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]; 
} 

我的问题是:调用-copyblock泄漏?编译器如何知道何时释放该块?仪器没有检测到泄漏,但是根据我对ARC的了解,这并不能说服我,这种情况得到正确处理。感谢您的任何信息!

回答

5

这将泄漏在保留/释放,但不应该在ARC泄漏。

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

(当然,正是你所看到的,一旦你通过组装,这不完全是简单的涉水。)

请注意,您可以通过只编译[block copy];简化组装。

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具有2的retainCount和这个释放它降低到1,但不为0,因此它不会被释放。您的选择被称为另一个线程上只有后,blockCopy再次释放,因为你的所谓的选择没有保留它,它最终会被deallocted。

+0

使用绝对之外很好的解释保留计数..... – bbum

相关问题