繁体   English   中英

自动释放如何在Objective-C中工作?

[英]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 StevensonObjective-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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM