didReceiveMemoryWarning、viewDidUnload 和 dealloc
Posted
技术标签:
【中文标题】didReceiveMemoryWarning、viewDidUnload 和 dealloc【英文标题】:didReceiveMemoryWarning, viewDidUnload and dealloc 【发布时间】:2011-07-01 11:54:56 【问题描述】:我浏览了很多帖子、我的书籍和 Apple Developer,并收集了我在使用这些方面需要的大部分理解。如果有好心人能确认我做对(或纠正我)并回答这两个问题,我将不胜感激。
非常感谢,
克里斯。
消息顺序 通常,消息将按以下顺序出现:
didReceiveMemoryWarning
viewDidUnload(可能由 1 引起)——显然只适用于 View Controller 类。
dealloc
didReceiveMemoryWarning
当系统内存不足时调用。
默认情况下,视图控制器注册了内存警告通知,并且在模板方法中,如果没有超级视图,调用 [super didReceiveMemoryWarning] 会释放视图,这是一种检查视图是否可见的方法或不。它通过将其属性设置为 nil 来释放视图。
Action - 释放你不需要的任何东西,可能会撤销你在 viewDidLoad 中设置的东西。不要释放 UI 元素,因为这些应该由 viewDidUnload 释放。
问题 1 - 即使视图可见,它似乎也会被调用,因此很难看到您可以安全释放的内容。了解这一点以及可以发布的一些示例将非常有帮助。
viewDidUnload
当不可见的 View Controller 的 View 属性设置为 nil 时调用,手动或最常见的是通过 didReceiveMemoryWarning。
viewDidUnload 方法在那里,您可以: - 清理你想要的任何东西,以节省额外的内存或 - 如果您保留了一些 IBOutlets,以帮助释放在卸载视图时不会释放的内存。
Action - 通常你在 dealloc 中释放的任何 IBOutlets,也应该在这个方法中被释放(并且引用设置为 nil)。请注意,如果属性设置为保留,则将它们设置为 nil 也会释放它们。
dealloc
在释放视图控制器对象时调用,当保留计数降至零时调用。
Action - 释放所有已被该类保留的对象,包括但不限于所有具有保留或复制的属性。
弹出视图控制器和内存
问题 2 - 弹出视图是否会将其从内存中删除?
【问题讨论】:
关于问题2:你的意思是从导航控制器中释放视图还是弹出视图控制器? @Robin 0 弹出视图控制器。 【参考方案1】:一些更正和建议:
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
,则viewDidUnload
方法将不会被调用。一个微妙的点是,即使在控制器收到didReceiveMemoryWarning
时,视图控制器的视图已经被释放并设置为 nil,所以实际上没有要为控制器卸载的视图,viewDidUnload
将被调用,如果你调用didReceiveMemoryWarning
的超类实现。
这就是为什么手动将视图控制器的 view
属性设置为 nil 不是一个好习惯的原因。如果这样做,您最好也发送viewDidUnload
消息。我想您对viewDidUnload
的理解更可取,但显然这不是当前的行为。
如果您的意思是通过“弹出”来“从父视图中移除”,它确实会减少视图的保留计数,但不一定会释放它。
如果您的意思是从 UINavigationController 中弹出,它实际上会减少视图控制器本身的保留计数。如果视图控制器没有被另一个对象保留,它将被释放,最好是它的视图。正如我所解释的,viewDidUnload
这次将不会被调用。
从技术上讲,保留计数可能不会降至零。该对象更有可能在不事先将计数设置为零的情况下被释放。
为了确保视图控制器本身通常不会因为内存警告而被默认行为释放。
【讨论】:
@MHC。这太好了,对这个有一个坚定的理解真的很好,现在我现在如何区分隐藏的视图。相信这也会对其他人有所帮助。谢谢。 如果我在 didReceiveMemoryWarning 中释放/设置一些缓存数据为零,我是否也应该在 viewDidUnload 中这样做?后者总是跟随前者吗? 是的,viewDidUnload 总是跟在 didReceiveMemoryWarning 之后。 所以我不应该需要把它都装进去? 没有。如果您期望 viewDidUnload 将被调用,则在此处释放数据。同样,不幸的是,viewDidUnload 不能保证在视图被卸载时被调用。如果要处理视图可以被其他人显式卸载的情况,则必须在其他地方处理。【参考方案2】:didReceiveMemoryWarning
...
Action - 释放你不需要的任何东西,可能会撤销你在 viewDidLoad 中设置的东西。
这是错误的。您在viewDidLoad
中重新创建的任何内容都应在viewDidUnload
中发布(并设置为nil
)。正如您在下面提到的,didReceiveMemoryWarning
在视图可见时也会被调用。在didReceiveMemoryWarning
中,您应该释放诸如缓存或其他您所持有的视图控制器之类的东西,可以在下次需要它们时延迟重新创建(即,通过手动实现它们的 getter)。
viewDidUnload
...
Action - 通常你在 dealloc 中释放的任何 IBOutlets,也应该在这个方法中被释放(并且引用设置为 nil)。请注意,如果属性设置为保留,那么将它们设置为 nil 也会释放它们。
正确。通常,您在 viewDidLoad 中创建的所有内容以及所有声明为 retain
的 IBOutlets 都应在此处释放并设置为 nil
。
dealloc
...
Action - 释放所有已被该类保留的对象,包括但不限于所有具有保留或复制的属性。
正确。值得注意的是,这包括您在viewDidUnload
中处理的所有对象,因为后者在dealloc
进程中没有被隐式调用(AFAIK,不完全确定)。这就是为什么必须在viewDidUnload
中将所有发布对象设置为nil
的原因,因为否则您可能会发布两次(首先在viewDidUnload
,然后再次在dealloc
;如果您将指针设置为nil
,则dealloc
中的释放调用将无效)。
弹出视图控制器和内存
问题 2 - 弹出视图是否会将其从内存中删除?
不一定。这是您不应该关心的实现细节。无论当前的做法是什么,Apple 都可以在下一个版本中改变它。
【讨论】:
感谢您的澄清和更正。我现在可以放心地去清理我的代码了。【参考方案3】:只是为了更新这个线程以使其与 ios6 相关:
viewDidUnload 和 viewWillUnload 在 iOS6 中已被弃用。这些方法永远不会被调用。
有关此方法和其他已弃用的方法,请参阅:http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/DeprecationAppendix/AppendixADeprecatedAPI.html
【讨论】:
【参考方案4】:从 iOS 6 开始,我们如何检查视图是否再次加载。由于“viewDidUnload”已被弃用。如果在“didReceiveMemoryWarning”警告后视图被删除,您确定会调用“loadView”和“viewDidload”吗?
【讨论】:
以上是关于didReceiveMemoryWarning、viewDidUnload 和 dealloc的主要内容,如果未能解决你的问题,请参考以下文章
iOS 6 中的 didReceiveMemoryWarning
应该将 viewDidUnload 中的哪些工作移至 didReceiveMemoryWarning?
当应用程序在后台时没有收到 didReceiveMemoryWarning
Swift 惰性变量和 didReceiveMemoryWarning