我查看过很多帖子,我的书籍和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 - 弹出视图会将其从内存中删除吗?
答案 0 :(得分: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 */
}
}
请注意不要使用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”。