在ARC(自动引用计数)的大多数情况下,我们根本不需要考虑Objective-C对象的内存管理。不允许再创建NSAutoreleasePools了,但是有一个新的语法:
@autoreleasepool {
…
}
我的问题是,当我不应该手动释放/自动释放时,为什么我还需要这个?
编辑:简单总结一下我从所有的回答和评论中得到的东西:
新语法:
@autoreleasepool{…}是用于
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
…
[pool drain];
更重要的是:
ARC uses autorelease as well as release.
It needs an auto release pool in place to do so.
ARC doesn't create the auto release pool for you. However:
The main thread of every Cocoa app already has an autorelease pool in it.
There are two occasions when you might want to make use of @autoreleasepool:
When you are in a secondary thread and there is no auto release pool, you must make your own to prevent leaks, such as myRunLoop(…) { @autoreleasepool { … } return success; }.
When you wish to create a more local pool, as @mattjgalloway has shown in his answer.
人们经常将ARC误解为某种垃圾收集或类似的东西。事实是,经过一段时间后,苹果公司的人(感谢llvm和clang项目)意识到Objective-C的内存管理(所有的保留和释放等)可以在编译时完全自动化。这是通过阅读代码,甚至在它运行之前!:)
为了这样做,只有一个条件:我们必须遵守规则,否则编译器将无法在编译时自动执行该过程。因此,为了确保我们永远不会违反规则,我们不允许明确地写释放、保留等。这些调用由编译器自动注入到代码中。因此在内部我们仍然拥有自动发行,保留,发行等内容。只是我们不需要再写了。
ARC的A在编译时是自动的,这比垃圾收集等运行时要好得多。
我们仍然有@autoreleasepool{…}因为它不违反任何规则,我们可以在任何需要的时候自由地创建/排泄我们的池:)。
ARC并没有摆脱保留、释放和自动释放,它只是为你添加了所需的。所以仍然有保留的调用,仍然有释放的调用,仍然有自动释放的调用,仍然有自动释放池。
他们对新的Clang 3.0编译器和ARC所做的另一个改变是,他们用@autoreleasepool编译器指令取代了NSAutoReleasePool。NSAutoReleasePool一直是一个特殊的"对象"他们这样做是为了使用它的语法不会与对象混淆所以它通常更简单一点。
所以基本上,你需要@autoreleasepool,因为仍然有自动释放池需要担心。您只是不需要担心添加自动释放调用。
使用自动释放池的示例:
- (void)useALoadOfNumbers {
for (int j = 0; j < 10000; ++j) {
@autoreleasepool {
for (int i = 0; i < 10000; ++i) {
NSNumber *number = [NSNumber numberWithInt:(i+j)];
NSLog(@"number = %p", number);
}
}
}
}
当然,这是一个非常做作的例子,但是如果你在外部for循环中没有@autoreleasepool,那么你将在以后释放100000000个对象,而不是每次释放10000个对象。
更新:
也可以看到这个答案- https://stackoverflow.com/a/7950636/1068248 -为什么@autoreleasepool与ARC无关。
更新:
我研究了一下这里发生的事情,并把它写在了我的博客上。如果你看一下这里,你会清楚地看到ARC在做什么,以及新样式@autoreleasepool以及它如何引入一个作用域,被编译器用来推断哪些保留、释放和自动释放是必要的。
人们经常将ARC误解为某种垃圾收集或类似的东西。事实是,经过一段时间后,苹果公司的人(感谢llvm和clang项目)意识到Objective-C的内存管理(所有的保留和释放等)可以在编译时完全自动化。这是通过阅读代码,甚至在它运行之前!:)
为了这样做,只有一个条件:我们必须遵守规则,否则编译器将无法在编译时自动执行该过程。因此,为了确保我们永远不会违反规则,我们不允许明确地写释放、保留等。这些调用由编译器自动注入到代码中。因此在内部我们仍然拥有自动发行,保留,发行等内容。只是我们不需要再写了。
ARC的A在编译时是自动的,这比垃圾收集等运行时要好得多。
我们仍然有@autoreleasepool{…}因为它不违反任何规则,我们可以在任何需要的时候自由地创建/排泄我们的池:)。
关于这个主题似乎有很多困惑(至少有80人可能对此感到困惑,并认为他们需要在他们的代码中添加@autoreleasepool)。
如果一个项目(包括它的依赖项)只使用ARC,那么@autoreleasepool永远不需要使用,也不会做任何有用的事情。ARC将在正确的时间处理释放对象。例如:
@interface Testing: NSObject
+ (void) test;
@end
@implementation Testing
- (void) dealloc { NSLog(@"dealloc"); }
+ (void) test
{
while(true) NSLog(@"p = %p", [Testing new]);
}
@end
显示:
p = 0x17696f80
dealloc
p = 0x17570a90
dealloc
一旦值超出范围,每个测试对象就会被释放,而不需要等待自动释放池被退出。(同样的事情发生在NSNumber的例子中;这只是让我们观察dealloc。)ARC不使用自动释放。
@autoreleasepool仍然被允许的原因是对于混合的ARC和非ARC项目,这些项目还没有完全过渡到ARC。
如果你调用非arc代码,它可能返回一个自动释放的对象。在这种情况下,上面的循环将会泄漏,因为当前的自动释放池将永远不会退出。这就是您希望在代码块周围放置@autoreleasepool的地方。
但是如果你已经完全完成了ARC转换,那么忘记autoreleasepool吧。