什么时候会释放一个自动释放的对象?

16

我是Objective-C的新手,正在努力理解内存管理以正确使用它。

在阅读了苹果公司出色的Cocoa内存管理编程指南之后,我的唯一关注点是在iPhone/iPod应用程序中实际释放自动释放对象的时间。我的理解是在运行循环的末尾。但是什么定义了应用程序中的运行循环呢?

因此,我想知道以下代码是否正确。假设有一个对象:

@implementation Test

- (NSString *) functionA {
    NSString *stringA;
    stringA = [[[NSString alloc] initWithString:@"Hello"] autorelease]
    return stringA;
}

- (NSString *) functionB {
    NSString *stringB;
    stringB = [self functionA];
    return stringB;
}

- (NSString *) functionC {
    NSString *stringC;
    stringC = [self functionB];
    return stringC;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    NSString* p = [self functionC];
    NSLog(@"string is %@",p);
}

@end

这段代码是否有效?

从上下文可以推断出functionA返回的NSString在functionB的范围内是有效的。但我不确定它在functionCviewDidLoad中是否有效。

谢谢!

2个回答

18

是的,你的函数是有效的,并且使用了正确的Cocoa约定来返回对象进行保留/释放/自动释放/复制。

回答你关于runloop的问题,在你的应用程序的main()函数中,它调用UIApplicationMain()。你可以想象UIApplicationMain看起来像这样:

void int UIApplicationMain (int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName) {
    UIApplication *app = /* create app using principalClassName */;
    [app setDelegate:/* create delegate using delegateClassName */];
    while (![app shouldTerminate]) {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        event = [app getNextEvent];
        [app dispatchEvent:event];
        [pool drain];
    }
}
那个 while 循环类似于 UIKit 实际执行的操作,每次循环都相当于通过 runloop 进行一次旅行,其中 getNextEvent 函数会阻塞等待某些事件的发生。所有方法通常都是从 dispatchEvent: 中调用的。您可以尝试在其中一个方法(例如 IBAction)中设置断点,并在调试器调用堆栈的顶部查看处理事件和运行循环的 UIKit 方法的名称。由于每个方法都是从该 while 循环中调用的,因此每次在对象上调用 autorelease 时,该对象都会被添加到运行循环中的外部池中。当当前事件完成分派时,池会被清空,这些对象最终将收到释放消息。
最后注意一下,可能会有多个autorelease池,并不总是在事件循环的结尾。有时您可能会在一次事件循环中分配数万个对象。当发生这种情况时,您可以在自己的方法中设置额外的内部自动释放池,以减少 autorelease 池中的自动释放对象数量。自动释放池可以堆叠。

我是否理解正确:如果我没有创建任何自动释放池,所有自动释放的变量都会一直保留在内存中,直到应用程序关闭? - Burjua
在系统框架中,像UIApplicationMain()这样的方法会在主线程的堆栈顶部为您创建一些自动释放池。但是,如果您启动了自己的线程并且没有创建池,则这些对象将泄漏。在这种情况下,自动释放方法会记录到控制台。 - Jon Hess
好的,谢谢。但是这很奇怪,通常的做法是使用返回自动释放对象的构造函数并且不释放它们,但实际上这等同于内存泄漏(内存会一直分配到应用程序关闭)。或者我没理解什么? - Burjua
由像UIApplicationMain这样的函数为您创建的自动释放池会在每次事件循环中被清空一次。因此,对象将非常频繁地消失。如果您创建自己的线程,然后在该线程上创建自动释放的对象,则需要定期清空和重置自动释放池。 - Jon Hess
好的,谢谢Jon,现在我明白了,唯一的问题是我不太清楚这种情况下的事件循环是什么,你能举个例子吗? - Burjua

0

这段代码没有问题。它将会按照预期编译并运行。

functionA 返回的 NSString 对象在返回时仍然有效,因为它被传递到下一个函数 (functionB),现在由他来跟踪。


3
“Passed down the stack” 可能不是最好的用语选择,因为它暗示堆栈被用于返回值,而这并不总是情况。 - Nick Moore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接