[英]How does autoreleasing work in Objective-C?
我只是阅读实用内存管理指南。
我对这段代码感到有些困惑:
- (void)printHello {
NSString *string;
string = [NSString stringWithFormat:@"Hello"];
NSLog(@"%@", string);
}
在我看来,字符串的引用计数为0.这是真的吗?
什么阻止字符串在我们调用NSLog(string)
之前被释放?
这在某种程度上等同于此:
- (void)printHello {
NSString *string;
string = [[[NSString stringWithFormat:@"Hello"] retain] autorelease];
NSLog(@"%@", string);
}
编辑 :类似地,此代码在实用内存管理指南中给出:
- (NSString *)fullName {
NSString *string = [NSString stringWithFormat:@"%@ %@", firstName, lastName];
return string;
}
何时以及如何释放返回值? 谁是老板? fullName
的调用者是否需要释放全名返回的字符串?
首先:
NSLog(string);
不要这样做。 (我刚刚意识到它来自Apple文档。很奇怪。) NSLog
的第一个参数是格式化字符串。 如果你的string
包含一些百分比转义,那么坏事就会发生。 正确的,如果稍长的方式是:
NSLog(@"%@", string);
现在到了这一点:自动释放的对象没有零保留计数。 他们保留计数1+并且对他们进行挂起的-1操作,这将在“未来很快”发生。
“很快将来”的确切含义取决于具体情况。 如果您在主线程上并且没有其他自动释放池,则自动释放的对象将在下一个runloop迭代中释放。 如果您有其他发布池,则不必如此:
// Let’s pretend this is a long loop and you don’t want to wait
// for the autoreleased objects to be collected by the main pool.
for (…) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *foo = [NSString stringWith…];
[pool drain];
// Now foo is no longer valid.
}
至于返回自动释放的对象,这是自动释放的主要用例之一。 你正在返回一个将很快消失的对象,但如果调用者感兴趣,他可以保留并接管所有权。 (就像你赦免图像一样,用燃烧的安全保险丝传递炸弹。如果来电者有兴趣,他会通过保留来放出保险丝。)如果来电者不感兴趣,可能他会忽略输出从一个函数或只是使用该值来构造一些其他对象,他没有做任何事情,对象将失去内存:
- (id) createObject {
return [NSString stringWith…];
}
- (void) interestedCaller {
NSString *value = [[self createObject] retain];
}
- (void) notInterestedCaller {
[self createObject]; // maybe just interested in side effects
NSString *differentString = [NSString stringWithString:[self createObject]];
}
这非常方便,使手动内存管理非常愉快。 您可能对运行循环和Scott Stevenson的Objective-C教程感兴趣。
严格来讲,
- (void)printHello {
NSString *string;
string = [NSString stringWithFormat:@"Hello"];
NSLog(@"%@", string);
}
不等于
- (void)printHello {
NSString *string;
string = [[[NSString stringWithFormat:@"Hello"] retain] autorelease];
NSLog(@"%@", string);
}
惯例是一个方法应该自动释放它返回的任何对象。 唯一的例外(AFAIK)是构造函数,它返回一个具有+1保留计数的对象。 由于[NSString stringWithFormat:]
返回一个对象。 在第一个片段中, stringWithFormat:
返回一个已经自动释放的对象。 第二个片段,你再次保留它,它将被释放两次(具有相同的效果,但第二个保留/自动释放对是多余的)。
好的,现在回答你的问题。 基本上,每次UIKit调用您的代码时,它都会创建一个NSAutoreleasePool
对象。 每次自动释放对象时,都会将其添加到此池中。 最后,当您的代码返回到UIKit时,它会调用池上的drain方法(即[pool drain]
)并释放已添加到池中的每个对象并释放池。 此外,自动释放池可以嵌套,因此如果您要创建大量自动释放的对象,则可以创建自己的池并将其耗尽。 它并不像听起来那么复杂。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.