本文共 2295 字,大约阅读时间需要 7 分钟。
自动释放池块提供了一种机制,您可以放弃对象的所有权,但避免立即释放它(例如从方法返回对象时)。通常,您不需要创建自己的自动释放池块,但在某些情况下,您必须或者这样做是有益的。
使用标记自动释放池块@autoreleasepool
,如以下示例所示:
@autoreleasepool { |
//创建自动释放对象的代码。 |
} |
在自动释放池块的末尾,在块中接收到autorelease
消息release
的对象被发送消息 - 对象release
在每次在块内发送消息时接收消息autorelease
。
与任何其他代码块一样,自动释放池块可以嵌套:
@autoreleasepool { |
// 。。 |
@autoreleasepool { |
// 。。 |
} |
。。。 |
} |
(您通常不会完全按上述方式查看代码;通常,一个源文件中的自动释放池块中的代码将调用另一个自动释放池块中包含的另一个源文件中的代码。)对于给定的autorelease
消息,将release
发送相应的消息在autorelease
发送消息的自动释放池块的末尾。
Cocoa 总是希望代码在自动释放池块中执行,否则自动释放的对象不会被释放而应用程序会泄漏内存。(如果您autorelease
在自动释放池块之外发送消息,Cocoa 会记录一个合适的错误消息。)AppKit 和 UIKit 框架处理自动释放池块中的每个事件循环迭代(例如鼠标按下事件或轻击)。因此,您通常不必自己创建自动释放池块,甚至不必查看用于创建池的代码。但是,有三种情况可能会使用您自己的自动释放池块:
如果您正在编写不基于 UI 框架的程序,例如命令行工具。
如果编写一个创建许多临时对象的循环。
您可以在循环内使用自动释放池块在下一次迭代之前处理这些对象。在循环中使用自动释放池块有助于减少应用程序的最大内存占用量。
如果你产生一个辅助线程。
一旦线程开始执行,您必须创建自己的自动释放池块;否则,您的应用程序将泄漏对象。(有关详细信息,请参阅。)
许多程序创建自动释放的临时对象。这些对象会添加到程序的内存占用空间,直到块结束。在许多情况下,允许临时对象累积直到当前事件循环迭代结束时不会导致过多的开销;但是,在某些情况下,您可能会创建大量临时对象,这些对象会大大增加内存占用,并且您希望更快地处置。在后面这些情况下,您可以创建自己的自动释放池块。在块结束时,临时对象被释放,这通常导致它们的释放,从而减少程序的内存占用。
以下示例显示了如何在for
循环中使用本地自动释放池块。
NSArray * urls = <#一个文件URL数组#>; |
for(NSURL * url in urls){ |
@autoreleasepool { |
NSError *错误; |
NSString * fileContents = [NSString stringWithContentsOfURL:url |
encoding:NSUTF8StringEncoding error:&error]; |
/ *处理字符串,创建和自动释放更多对象。* / |
} |
} |
该for
循环一次处理一个文件。在块结束时释放在自动释放池块内fileContents
发送autorelease
消息的任何对象(例如)。
在自动释放池块之后,您应该将块中自动释放的任何对象视为 “已处置”。不要向该对象发送消息或将其返回给您的方法的调用者。如果必须使用自动释放池块之外的临时对象,则可以通过向retain
块内的对象发送消息然后在块之后发送它autorelease
来执行此操作,如以下示例所示:
- (id)findMatchingObject:(id)anObject { |
id匹配; |
while(match == nil){ |
@autoreleasepool { |
/ *执行创建大量临时对象的搜索。* / |
match = [self expensiveSearchForObject:anObject]; |
if(match!= nil){ |
[匹配保留]; / *保持匹配。* / |
} |
} |
} |
return [match autorelease]; / *让匹配去并返回它。* / |
} |
发送retain
到match
自动释放池块并autorelease
在自动释放池块之后发送到它并延长其生命周期match
并允许它在循环外接收消息并返回给调用者findMatchingObject:
。
Cocoa 应用程序中的每个线程都维护自己的自动释放池块堆栈。如果您正在编写仅基于 Foundation 的程序或者分离线程,则需要创建自己的自动释放池块。
如果您的应用程序或线程长寿并且可能生成大量自动释放的对象,则应使用自动释放池块(如主线程上的 AppKit 和 UIKit); 否则,自动释放的对象会累积,并且您的内存占用会增加。如果您的分离线程没有进行 Cocoa 调用,则不需要使用自动释放池块。
注意: 如果使用 POSIX 线程 API 而不是创建辅助线程NSThread
,除非 Cocoa 处于多线程模式,否则不能使用 Cocoa。Cocoa 仅在分离其第一个NSThread
对象后才进入多线程模式。要在辅助 POSIX 线程上使用 Cocoa,您的应用程序必须首先分离至少一个NSThread
可以立即退出的对象。您可以使用NSThread
类方法测试 Cocoa 是否处于多线程模式。
转载地址:http://qqhwn.baihongyu.com/