didReceiveMemoryWarning,viewDidUnload和dealloc

Chr*_*ris 18 iphone memory-management uiviewcontroller

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

非常感谢,

克里斯.

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

  • didReceiveMemoryWarning

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

  • 的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 - 弹出视图是否将其从内存中删除?

MHC*_*MHC 31

一些更正和建议:

  • didReceiveMemoryWarning 做法

如你所说,控制器的默认实现didReceiveMemoryWarning如果"可以安全地"发布它的视图.虽然从Apple的文档中不清楚"安全这样做"的意思是,它通常被认为没有超级视图(因此目前无法看到视图),并且其loadView方法可以毫无问题地重建整个视图.

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

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

因此,在你的didReceiveMemoryWarning,首先调用超类实现,如果它的视图被卸载,然后释放自定义数据,因为你知道loadView并且viewDidLoad肯定会再次调用.例如,

- (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 */
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • viewDidUnload 方法

viewDidUnload视图控制器因内存警告而卸载视图时调用.例如,如果从superview中删除视图并将view控制器的属性设置为nil,viewDidUnload不会调用方法.一个微妙的观点是,即使视图控制器的视图已经被释放并且在控制器接收时设置为nil didReceiveMemoryWarning,因此实际上没有视图可以为控制器卸载,viewDidUnload如果调用超类的实现,则会调用didReceiveMemoryWarning.

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

  • 弹出视图控制器

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

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

  • 其他...

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

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


Ole*_*ann 8

didReceiveMemoryWarning

...

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

这是错的.您重新创建的任何内容viewDidLoad都应该被释放(并设置为nil)viewDidUnload.如下所述,didReceiveMemoryWarning当视图可见时也会调用.在didReceiveMemoryWarning,你应该释放像你持​​有的缓存或其他视图控制器之类的东西,可以在下次需要时懒洋洋地重新创建(即通过手动实现他们的getter).

viewDidUnload

...

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

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

的dealloc

...

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

正确.值得注意的是,这包括你处理的所有对象,viewDidUnload因为后者在dealloc进程中没有被隐式调用(AFAIK,并不完全确定).这就是为什么必须将所有版本对象设置为nilin,viewDidUnload因为否则你冒险释放两次(先进入viewDidUnload,然后再进入dealloc;如果你设置指针nil,则释放调用dealloc将无效).

弹出视图控制器和内存

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

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