自動釋放池block提供一種機制,你可以放棄一個對象的所有權(quán)彩匕,但避免立即被回收(例如當(dāng)一個方法返回一個對象)腔剂。通常,你不需要創(chuàng)建自己的自動釋放池block推掸,但也有一些情況下桶蝎,你必須這么做驻仅,或者這么做是有益的谅畅。
關(guān)于自動釋放池block
使用 @autoreleasepool
標(biāo)記自動釋放池block,見下面的例子:
<pre><code>
@autoreleasepool {
// Code that creates autoreleased objects.
}
</pre></code>
在自動釋放池block的結(jié)束噪服,block中接收到autorelease
消息的對象會接收到release
消息毡泻,即接收到release
消息的對象在block中會受到autorelease
消息。
像其他的代碼block粘优,自動釋放池block可以嵌套:
<pre><code>
@autoreleasepool {
// . . .
@autoreleasepool {
// . . .
}
. . .
}
</pre></code>
(通常你不會看到如上的代碼仇味;通常一個源文件中的自動釋放池block中的代碼可能會調(diào)用另一個包含自動釋放池block的源文件呻顽。)對于一個給定autorelease
消息,相應(yīng)的release
消息在自動釋放池block的結(jié)束發(fā)送autorelease
消息丹墨。
Cocoa希望代碼在自動釋放池block中執(zhí)行廊遍,否則生成的對象不能被釋放,應(yīng)用內(nèi)存泄露贩挣。(如果你在自動釋放池block之外發(fā)送autorelease
消息喉前,Cocoa會記錄錯誤消息。)AppKit和UIKit框架在自動釋放池block中處理每個事件循環(huán)迭代(如鼠標(biāo)點擊事件)王财。因此卵迂,通常你不需要自己創(chuàng)建自動釋放池。然而绒净,有三種情況你可能會使用自己的自動釋放池block:
- 如果你正在編寫不基于UI 框架的程序见咒,比如命令行工具。
- 如果你編寫的循環(huán)創(chuàng)建了很多臨時對象挂疆。
你可以在循環(huán)中使用自動釋放池block改览,在下次迭代前處理這些對象。在循環(huán)中使用自動釋放池block囱嫩,有助于減少應(yīng)用程序的內(nèi)存占用恃疯。
- 你生成了一個輔助線程。
一旦線程開始執(zhí)行墨闲,你必須自己創(chuàng)建自動釋放池lock今妄。否則,應(yīng)用將泄漏對象鸳碧。(詳情參見自動釋放池block和線程( Autorelease Pool Blocks and Threads))
使用本地自動釋放池block減少內(nèi)存占用峰值
許多應(yīng)用程序創(chuàng)建的臨時對象都是自動釋放的盾鳞。這些對象添加到應(yīng)用內(nèi)存中直到block結(jié)束。在許多情況下瞻离,允許臨時對象積累到當(dāng)前時間循環(huán)的最后腾仅,這樣不會導(dǎo)致過度開銷;然而套利,在某些情況推励,你可能會創(chuàng)建大量的臨時對象,大幅度增加內(nèi)存占用肉迫,同時你希望能更快的處理验辞。在后面這種情況,你可以自己創(chuàng)建自動釋放池block喊衫。在block的結(jié)束跌造,臨時對象被釋放,這通常可以回收這些對象從而減少應(yīng)用程序內(nèi)存占用壳贪。
下面的例子展示了如何在for循環(huán)中使用本地自動釋放池block陵珍。
<pre><code>
NSArray *urls = <# An array of file URLs #>;
for (NSURL *url in urls) {
@autoreleasepool {
NSError *error;
NSString *fileContents = [NSString stringWithContentsOfURL:url
encoding:NSUTF8StringEncoding
error:&error];
/* Process the string, creating and autoreleasing more objects. */
}
}
</pre></code>
for循環(huán)一次處理一個文件。在自動釋放池block中的任何對象(例如违施,fileContents
)發(fā)送一個autorelease
消息互纯,會在block結(jié)束被釋放。
在自動釋放池block后,可以認(rèn)為對象都自動釋放。不要給該對象發(fā)送消息或返回方法調(diào)用拯钻。如果你必須在自動釋放池block之外使用臨時對象峭判,可以在block中發(fā)送retain消息到對象,在block之后發(fā)送autorelease
消息,如本例所示:
<pre><code>
–(id)findMatchingObject:(id)anObject {
id match;
while (match == nil) {
@autoreleasepool {
/* Do a search that creates a lot of temporary objects. */
match = [self expensiveSearchForObject:anObject];
if (match != nil) {
[match retain]; /* Keep match around. */
}
}
}
return [match autorelease]; /* Let match go and return it. */
}
</pre></code>
在自動釋放池block中發(fā)送retain
消息到match
,在自動釋放池block拓展match
生命周期后發(fā)送autorelease
消息,并允許它接收循環(huán)外的消息秆乳,返回到調(diào)用findMatchingObject:
。
自動釋放池block和線程
Cocoa應(yīng)用中的每個線程維護自己的自動釋放池block的堆棧钻哩。如果你正在編寫框架應(yīng)用或你要分離線程屹堰,你需要自己創(chuàng)建自動釋放池block。
如果你的應(yīng)用或線程是長期存在的并可能生成大量的自動釋放對象街氢,你應(yīng)該使用自動釋放池block(如AppKit和UIKit做主線程)扯键;否則,自動釋放對象積累珊肃,你的內(nèi)存占用增加荣刑。如果Cocoa不調(diào)用你的分離線程,你不需要使用自動釋放池block伦乔。
注意:如果你使用POSIX線程API而不是
NSThread
創(chuàng)建輔助線程厉亏,不能使用Cocoa除非Cocoa處于多線程模式。Cocoa只有在分離第一個NSThread
對象后才會進入多線程模式烈和。在輔助POSIX線程中使用Cocoa爱只,你的應(yīng)用程序首先分離至少在一個NSThread
對象,這個線程可以立即退出招刹。你可以使用NSThread
類的isMultiThreaded
方法測試Cocoa是否處于多線程模式恬试。