【问题标题】:Should an autorelease call crash if there is no nsautoreleasepool declared?如果没有声明 nsautoreleasepool,自动释放调用是否会崩溃?
【发布时间】:2012-02-06 07:31:01
【问题描述】:

对不起,我是 cocoa 编程的新手,我不确定我是否真的了解 nsautoreleasepool 的工作原理。

我读到的每一个地方都说 NSAutoreleasePool 负责所有自动释放调用(谈论最后一个 NSAutoreleasePool 声明)。

考虑以下代码:

int main(int argc, char *argv[]) {

    //NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, nil);
    //[pool release];
    return retVal;
}

在我的应用程序的某些时候,我也会有类似的东西:

NSString* b = [[NSString alloc] initWithFormat:@"%d", 10];
[b autorelease];

考虑到我在任何地方都没有NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];...[b autorelease]; 不应该使应用程序崩溃吗?但该应用程序似乎运行良好。

观察:我不打算在没有 NSAutoreleasePool 的情况下编写应用程序,我只是想弄清楚它是如何工作的。这个事实让我怀疑我所知道的。

【问题讨论】:

    标签: iphone cocoa-touch autorelease nsautoreleasepool


    【解决方案1】:

    您只会在控制台中收到一条警告,即没有自动释放池并且对象已泄漏。

    如果您真的想了解自动释放池,请阅读Mike Ash's Let's build NSAutoreleasePool

    【讨论】:

    • 这没有发生。当我触摸我正在调用的按钮时: NSString* b = [[NSString alloc] initWithFormat:@"%d", 10]; [b 自动释放];我有 NSLog 和 UIAlert 我确定该方法正在被调用......它在控制台中没有显示任何错误,就像没有任何问题一样。
    • 啊,我认为您在这里做的“错误”是您已经运行了一个 runloop (UIApplicationMain)。将UIApplicationMain 行替换为[[[NSString alloc] initWithFormat:@"%d", 10] autorelease];,您将收到泄漏消息。如果您创建一个新线程(例如通过performSelectorInBackground:withObject:)并在不先创建自动释放池的情况下运行自动释放测试,您也会得到它。
    • (PS:runloop 创建自动释放池,这就是为什么你的对象实际上没有泄漏)
    【解决方案2】:

    来自documentation for NSAutoreleasePool...

    在引用计数环境中,Cocoa 期望有一个 自动释放池始终可用。如果没有游泳池, 自动释放的对象不会被释放,并且您会泄漏内存。在这个 在这种情况下,您的程序通常会记录适当的警告消息。

    这很不言自明。您是否在控制台中收到与此相关的任何消息?

    【讨论】:

    • 不,我没有。这就是我觉得奇怪的地方。我在 main 方法中评论了 NSAutorelease 池的声明,我调用了 [b autorelease],我在控制台或任何地方都没有看到任何警告或错误消息。
    【解决方案3】:

    直接来自apple documentation

    NSApplication 类设置自动释放池( NSAutoreleasePool 类)在初始化期间和事件内部 循环——具体来说,在其初始化(或 sharedApplication)中 并运行方法。同样,Application Kit 添加的方法 NSBundle 在加载 nib 文件时使用自动释放池。 这些自动释放池在 相应的 NSApplication 和 NSBundle 方法。通常,一个 应用程序在事件循环运行时创建对象或 通过从 ni​​b 文件加载对象,因此通常缺乏访问权限 不是问题。但是,如果您确实需要在内部使用 Cocoa 类 main() 函数本身(除了加载 nib 文件或 实例化 NSApplication),你应该创建一个自动释放池 在使用类之前,然后在完成后释放池。 如需更多信息,请参阅NSAutoreleasePool in the Foundation Framework Reference

    【讨论】:

      【解决方案4】:

      UIApplicationMain() 确保主线程运行事件循环,因此您的应用程序可以处理事件(例如用户输入、计时器事件等),并且事件循环在开始迭代之前创建一个自动释放池,并在完成后释放它机智的。从主线程的偶数循环调用的所有代码(例如所有 UI 代码)总是有一个自动释放池,您无需执行任何操作。您只需要在使用与主线程不同的线程时管理 autoreleasepool(但仅在实际使用线程时!使用 DispatchQueues 或 OperationQueues 时,这些也会为您管理 autoreleasepool)并且在极少数情况下您希望使用它们围绕循环以保持您的内存占用较小(自动释放池收集对象以供以后释放,但有时您不希望它收集太多对象从而变得太大,而是希望在您自己的循环的每次迭代中清除它,在这种情况下你需要自己管理一个)。在大多数情况下,您不需要了解任何关于 autoreleasepools 的知识,您可以编写一个完整的、功能齐全的应用程序,而无需每个人都听说过 autoreleasepools。您只需要知道何时必须对您拥有的对象调用 autorelease,这仅适用于非 ARC 代码,因为 ARC 编译器会自动为您决定。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-09-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多