是否有必要在 Swift 程序中使用自动发布池?

这个 WWDC14演示的第17页上写着

使用 Objective-C? 仍然需要管理自动发布池
Autorelease asepool {/* code */}

这是什么意思? 这是否意味着,如果我的代码库没有任何 Objective-C 文件,autoreleasepool {}是不必要的?

相关问题的答案中,有一个 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);
}
}
}
}

如果上面的代码被翻译成 Swift 而 autoreleasepool被丢弃,Swift 是否足够聪明,知道 number变量应该在第一个 }之后被释放(就像其他语言一样) ?

53503 次浏览

If you would use it in the equivalent Objective-C code, then you would use it in Swift.

will Swift be smart enough to know that the number variable should be released after the first }

Only if Objective-C does. Both operate along the Cocoa memory management rules.

Of course ARC knows that number goes out of scope at the end of that iteration of the loop, and if it retained it, it will release it there. However, that does not tell you whether the object was autoreleased, because -[NSNumber numberWithInt:] may or may not have returned an autoreleased instance. There is no way you can know, because you don't have access to the source of -[NSNumber numberWithInt:].

The autoreleasepool pattern is used in Swift when returning autorelease objects (created by either your Objective-C code or using Cocoa classes). The autorelease pattern in Swift functions much like it does in Objective-C. For example, consider this Swift rendition of your method (instantiating NSImage/UIImage objects):

func useManyImages() {
let filename = pathForResourceInBundle
    

for _ in 0 ..< 5 {
autoreleasepool {
for _ in 0 ..< 1000 {
let image = NSImage(contentsOfFile: filename)
}
}
}
}

If you run this in Instruments, you'll see an allocations graph with 5 small hills (because outer for-loop), like the following:

with autoreleasepool

But if you do it without the autorelease pool, you'll see that peak memory usage is higher:

without autoreleasepool

The autoreleasepool allows you to explicitly manage when autorelease objects are deallocated in Swift, just like you were able to in Objective-C.

Note: When dealing with Swift native objects, you generally will not receive autorelease objects. This is why the presentation mentioned the caveat about only needing this when "working with Objective-C", though I wish Apple was more clear on this point. But if you're dealing with Objective-C objects (including Cocoa classes), they may be autorelease objects, in which case this Swift rendition of the Objective-C @autoreleasepool pattern is still useful.

@autoreleasepool can be used in Objective-C and Swift code to guarantee working with Objective-C code which relies on autorelease

[Under the hood]