据我所知,任何使用 alloc , new 或 copy 创建的内容都需要手动发布。例如:
int main(void) {
NSString *string;
string = [[NSString alloc] init];
/* use the string */
[string release];
}
我的问题是,这不是有效吗?:
int main(void) {
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
NSString *string;
string = [[[NSString alloc] init] autorelease];
/* use the string */
[pool drain];
}
答案 0 :(得分:65)
是的,你的第二个代码snippit是完全有效的。
每次--autorelease被发送到一个对象,它被添加到最里面的自动释放池。当池被耗尽时,它只是发送-release给池中的所有对象。
自动释放池只是一种便利,允许您推迟发送 - 直到“以后”。 “稍后”可能会在多个地方发生,但Cocoa GUI应用程序中最常见的是在当前运行循环周期结束时。
答案 1 :(得分:37)
由于drain
和release
的功能似乎引起了混淆,因此在此可能值得澄清(尽管the documentation已涵盖这一点......)。
严格来说,从大图来看,drain
等同于release
:
在引用计数环境中,drain
执行与release
相同的操作,因此两者在这种意义上是等效的。要强调,这意味着如果您使用drain
而不是release
,则不会泄漏池。
在垃圾收集环境中,release
是无操作的。因此它没有效果。另一方面,drain
包含一个收集器的提示,它应该“在需要时收集”。因此,在垃圾收集环境中,使用drain
有助于系统平衡收集扫描。
答案 2 :(得分:17)
正如已经指出的那样,您的第二个代码段是正确的。
我想建议一种更简洁的方法来使用适用于所有环境的自动释放池(引用计数,GC,ARC),并避免排放/释放混淆:
int main(void) {
@autoreleasepool {
NSString *string;
string = [[[NSString alloc] init] autorelease];
/* use the string */
}
}
在上面的示例中,请注意 @autoreleasepool 块。记录在案here。
答案 3 :(得分:7)
不,你错了。文档清楚地表明,在非GC下,-drain相当于-release,这意味着NSAutoreleasePool将不泄露。
答案 4 :(得分:0)
我从Apple那里读到的内容: “在自动释放池块的末尾,在块中接收到自动释放消息的对象被发送一个释放消息 - 一个对象在每次在块中发送自动释放消息时都会收到释放消息。”
答案 5 :(得分:0)
发送自动释放而不是释放到对象会延长该对象的生命周期,至少直到池本身耗尽(如果随后保留该对象,它可能会更长)。一个对象可以多次放入同一个池中,在这种情况下,每次将它放入池中时都会收到一条释放消息。
答案 6 :(得分:-2)
是和否。你最终会释放字符串内存但是如果你在垃圾收集(非内存管理)环境下运行它,则使用drain而不是release来将NSAutoreleasePool对象“泄漏”到内存中。这种“泄漏”只会使NSAutoreleasePool的实例“无法访问”,就像在GC下没有强指针的任何其他对象一样,并且该对象将在下次GC运行时被清除,这很可能是在调用{{1 }}:
漏极
在垃圾收集环境中,如果自上次收集后分配的内存大于当前阈值,则触发垃圾收集;否则表现为释放。 ... 在垃圾收集环境中,此方法最终调用
-drain
。
否则,它类似于objc_collect_if_needed
在非GC下的行为,是的。正如其他人所说,-release
是GC下的无操作,因此确保池在GC下正常运行的唯一方法是通过-release
和-drain
非GC工作与非GC下的-drain
完全相同,并且可以说更清楚地传达其功能。
我应该指出你的语句“用new,alloc或init调用的任何东西”不应该包含“init”(但应该包括“copy”),因为“init”不分配内存,它只设置object(构造函数方式)。如果你收到一个alloc'd对象而你的函数只调用了init,你就不会释放它:
-release
它不会消耗比你已经开始使用的内存更多的内存(假设init没有实例化对象,但你无论如何都不负责)。