1. 内存警告的说明
在iOS6.0之后,不再支持viewWillUnload 和 viewDidUnload。但依然支持didReceiveMemoryWarning。之所以不支持viewWillUnload和 viewDidUnload,官方文档的解释是:当view不在window视图中时,系统会自动释放view中的耗内存的资源,view中剩余的资源所占内存极小,不值得系统为了节省内存而自动去释放,然后再重新创建视图层次。
The answer I eventually got back from Apple:
Your "large resources" happen to be images that you've loaded cached via +imageNamed:. Because they are loaded cached, they are exempted from the automatic cleanup. Generally only content generated via -drawRect: or by Core Animation is automatically released here. Because your views continue to exist, they continue to hold a reference to these cached images, and we can't purge them on memory warning either
2. 导致的问题
如上导致的问题是:系统会自动控制释放view,但是其retain/strong属性的子view无法得到释放。
3. 官方的解决
- (void)didReceiveMemoryWarning |
{ |
[super didReceiveMemoryWarning]; |
// Add code to clean up any of your own resources that are no longer necessary. |
if ([self.view window] == nil) |
{ |
// Add code to preserve data stored in the views that might be |
// needed later. |
|
// Add code to clean up other strong references to the view in |
// the view hierarchy. |
self.view = nil; |
} |
官方代码的理解:
[self.view window] == nil 这段代码和ios5中调用viewWillUnload的判断条件一样:满足self.view存在;self.view可被释放,即不在任何视图层次中。
官方代码的问题:
在 [self.view window]== nil 中,如果当前的view未创建,接受到了内存警告,则该段代码导致系统生成view,然后在self.view= nil又释放掉了。
4. 可以采用的实现方式
// will not be called in iOS 6, see iOS docs
- (void)viewWillUnload
{
[super viewWillUnload];
[selfmy_viewWillUnload];
}
// will not be called in iOS 6, see iOS docs
- (void)viewDidUnload
{
[super viewDidUnload];
[selfmy_viewDidUnload];
}
// in iOS 6, view is no longer unloaded so do it manually
- (void)didReceiveMemoryWarning
{
[superdidReceiveMemoryWarning];
if ([self isViewLoaded]&& [self.viewwindow] ==nil) {
[selfmy_viewWillUnload];
self.view = nil;
[selfmy_viewDidUnload];
}
}
- (void)my_viewWillUnload
{
// prepare to unload view
}
- (void)my_viewDidUnload
{
// the view is unloaded, clean up as normal
}
说明:
l [self.view window] == nil 的基础上增加了另外一个条件[selfisViewLoaded]。[self isViewLoaded]表示系统调用了loadView,并生成了view。这样就可以避免上面所说到的问题。
l 这里在iOS5上也不会出现重复调用my_viewWillUnload和my_viewDidUnload,在didReceiveMemoryWarning 中,系统首先调用了viewWillUnload和viewDidUnload,这时self.view为空,不满足[self isViewLoaded]。