didReceiveMemoryWarning,viewDidUnload和dealloc

时间:2011-02-21 18:52:06

标签: iphone memory-management uiviewcontroller

我查看过很多帖子,我的书籍和Apple Developer,并收集了大部分使用这些内容所需的理解。如果某个善良的人能够证实我做对了(或纠正了我)并回答了这两个问题,我将非常感激。

非常感谢,

克里斯。

消息顺序 通常,消息将按以下顺序显示:

  • didReceiveMemoryWarning

  • viewDidUnload(可能由1引起) - 显然只适用于View Controller类。

  • 的dealloc

didReceiveMemoryWarning

系统内存不足时调用。

默认情况下,视图控制器已注册内存警告通知,并且在模板方法中,如果没有超级视图,则调用[super didReceiveMemoryWarning]会释放视图,这是一种检查视图是否可见的方法或不。它通过将其属性设置为nil来释放视图。

操作 - 释放您不需要的任何内容,可能会撤消您在viewDidLoad中设置的内容。不要释放UI元素,因为这些元素应该由viewDidUnload释放。

问题1 - 即使View可见,似乎也会调用它,因此很难看到你可以安全释放的内容。了解这一点以及可以发布的一些示例将非常有用。

viewDidUnload

每当不可见的View Controller的View属性设置为nil时调用,手动或最常见的是通过didReceiveMemoryWarning。

viewDidUnload方法在那里,您可以: - 清理你想要的任何东西,以节省额外的记忆或 - 如果你保留了一些IBOutlets,以帮助释放内存,否则视图将被卸载。

操作 - 通常在dealloc中释放的任何IBOutlet也应该在此方法中释放(并且引用设置为nil)。请注意,如果将属性设置为retain,则将它们设置为nil也会释放它们。

的dealloc

取消分配视图控制器对象时调用,当保留计数降为零时,将调用此对象。

操作 - 释放该类保留的所有对象,包括但不限于具有保留或复制的所有属性。

弹出视图控制器和内存

问题2 - 弹出视图会将其从内存中删除吗?

4 个答案:

答案 0 :(得分:31)

一些更正和建议:

  • didReceiveMemoryWarning练习

正如你所说,如果“安全的话”,控制器的默认实现didReceiveMemoryWarning会释放它的视图。虽然从Apple的文档中不清楚“安全这样做”是什么意思,但它通常被认为没有超级视图(因此目前无法看到视图),并且其loadView方法可以重建整个视图没有问题。

覆盖didReceiveMemoryWarning时的最佳做法是,不要尝试释放任何视图对象。如果不再需要,只需发布​​您的自定义数据即可。关于视图,只需让超类的实现处理它们。

但是,有时数据的必要性可能取决于您的视图状态。在大多数情况下,这些自定义数据是使用viewDidLoad方法设置的。在这些情况下,“安全发布自定义数据”意味着您知道在视图控制器再次使用自定义数据之前将调用loadViewviewDidLoad

因此,在didReceiveMemoryWarning中,首先调用超类实现,如果其视图已卸载,则释放自定义数据,因为您知道将再次调用loadViewviewDidLoad当然。例如,

- (void)didReceiveMemoryWarning {
    /* This is the view controller's method */
    [super didReceiveMemoryWarning];
    if (![self isViewLoaded]) {
        /* release your custom data which will be rebuilt in loadView or viewDidLoad */
    }
}

请注意不要使用self.view == nil,因为self.view会假定某人需要该视图,并会立即再次加载视图。

  • viewDidUnload方法
视图控制器由于内存警告而卸载视图时,会调用

viewDidUnload。例如,如果从超级视图中删除视图并将控制器的view属性设置为nil,则{strong}> 方法将调用 。一个微妙的观点是,即使视图控制器的视图已经被释放并且在控制器接收到viewDidUnload时设置为nil,因此实际上没有视图可以为控制器卸载,didReceiveMemoryWarning将如果调用超类的viewDidUnload实现,则调用。

这就是为什么手动将视图控制器的didReceiveMemoryWarning属性设置为nil不是一个好习惯。如果您这样做,您也可以更好地发送view消息。我想你对viewDidUnload的理解更为可取,但显然这不是当前的行为。

  • 弹出视图控制器

如果您的意思是“通过'弹出'从超级视图中删除',它确实会减少视图的保留计数,但不一定会取消分配。

如果您的意思是从UINavigationController弹出,它实际上减少了视图控制器本身的保留计数。如果视图控制器没有被另一个对象保留,则它将被取消分配,最好是其视图。正如我所解释的那样,viewDidUnload这次将

  • 其他...

从技术上讲,保留计数可能不会降至零。如果不事先将计数设置为零,则更有可能仅释放对象。

为了确保,由于内存警告,视图控制器本身通常不会被默认行为释放。

答案 1 :(得分:8)

  

didReceiveMemoryWarning

     

...

     

操作 - 释放您不需要的任何内容,可能会撤消您在viewDidLoad中设置的内容。

这是错误的。您在viewDidLoad中重新创建的任何内容都应在nil中释放(并设置为viewDidUnload)。如下所述,当视图可见时,也会调用didReceiveMemoryWarning。在didReceiveMemoryWarning中,您应该释放缓存或其他视图控制器等内容,这些内容可以在下次需要时懒惰地重新创建(即通过手动实现其getter)。

  

viewDidUnload

     

...

     

操作 - 通常在dealloc中释放的任何IBOutlet也应该在此方法中释放(并且引用设置为nil)。请注意,如果将属性设置为retain,则将它们设置为nil也会释放它们。

正确。通常,您在viewDidLoad中创建的所有内容以及声明为retain的所有IBOutlet都应该在此处释放并设置为nil

  

的dealloc

     

...

     

操作 - 释放该类保留的所有对象,包括但不限于具有保留或复制的所有属性。

正确。值得注意的是,这包括您在viewDidUnload中处理的所有对象,因为后者未在dealloc进程中被隐式调用(AFAIK,并非完全确定)。这就是为什么必须在nil中将所有版本对象设置为viewDidUnload,因为否则您可能会冒两次释放内容(首先在viewDidUnload中,然后再在dealloc中;如果您设置了指向nil的指针,dealloc中的释放调用无效。

  

弹出视图控制器和内存

     

问题2 - 弹出视图会将其从内存中删除吗?

不一定。这是一个您不应该关注的实现细节。无论目前的做法是什么,Apple都可以在下一个版本中对其进行更改。

答案 2 :(得分:3)

只是为了更新这个线程以使其与iOS6相关:

在iOS6中不推荐使用viewDidUnload和viewWillUnload。永远不会调用这些方法。

对于此方法和其他已弃用的方法,请参阅:http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/DeprecationAppendix/AppendixADeprecatedAPI.html

答案 3 :(得分:0)

从iOS 6开始,我们如何检查视图是否再次加载。由于“viewDidUnload”已弃用。如果在“didReceiveMemoryWarning”警告之后删除视图,您确定会调用“loadView”和“viewDidload”。