背景:
我有一个标签栏应用程序.每个选项卡都包含导航控制器,允许用户从一个视图转换到另一个视图,显示数据的向下钻取信息(每个视图由视图控制器处理,每个视图控制器类都有didReceiveMemoryWarning
方法).通过从Web服务中提取数据来填充列表.
问题:
当我使用iPhone模拟器的"硬件>模拟内存警告"选项时,didReceiveMemoryWarning
将为所有视图控制器调用该方法 - 即使是用户正在查看的控制器.我不想清除活动视图控制器正在使用的任何内容.我怎样才能做到这一点?
由于内存警告,在数据发布后,哪种方法应该重新加载数据?(我看到viewDidLoad
当用户返回到该视图时,包含表视图调用方法的视图控制器类,但如果视图包含(比如UIWebView),viewDidLoad
则不调用方法.为什么会这样?)
编辑(2009年1月30日星期五 - 03:10 PM)
(注意:我正在使用"界面"构建器来创建视图,并且loadView
方法已被注释掉.)
因此,当视图控制器收到内存警告消息时,这些是执行的步骤:
以下方法称为:
- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; }
由于调用[super didReceiveMemoryWarning]
,[self setView:nil]
自动调用?
如果应清除任何资源,setView
则应覆盖方法以清除本地资源.
[self setView:nil]
如果视图当前处于活动状态,则不会调用(默认情况下).对? - 我真的很好奇哪种方法可以做出这个决定以及如何做出决定?
可以请你确认一下.另外,我在这种方法myObject = nil
后遇到错误,但myObject
在dealloc
控制器类的方法中释放后添加修复了问题.谢谢.
这是一个老问题,但我没有看到正确的答案,所以这里是:
当收到内存警告时,-didReceiveMemoryWarning
将在所有视图控制器中调用它们,无论它们是否是"当前"控制器.视图控制器只是监听内存警告事件广播.
如果在内存警告时未使用视图控制器的视图,则控制器将通过将属性设置为nil来卸载它.如何知道视图是否被使用?由视图的-superview
属性.如果view.superview
为nil,则视图不是任何树的一部分,可以安全卸载.
一旦发生这种情况,控制器-viewDidUnload
就会被调用.这是卸载任何插座的正确位置,以及任何可以重新创建的插座-viewDidLoad
.
那是-didReceiveMemoryWarning
为了什么?您的控制器可能具有在访问之前不会实例化的对象.例如,您可能有一个控制器,有时需要从文件中获取大量数据,但并非总是如此.您可以为此设置一个属性,如下所示:
- (NSData*)bigChunkOfData { // Get data from our instance variable _data, read from disk if necessary if (_data == nil) { _data = [[NSData alloc] initWithContentsOfFile:@"/path/to/data"]; } return _data; }
这将首次从磁盘读取数据,然后将其保存在实例变量中.由于_data
变量是按需创建的,因此我们可以安全地在低内存情况下卸载它:它将在下次需要时再次创建.
- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; [_data release]; _data = nil; // <-- Very important: don't leave strong references dangling. }
我像这样清理:
-(void)setView:(UIView*)view { [super setView:view]; if(view == nil) { // Our view has been cleared, therefore we should clean up everything // we are not currently using ....
setView:nil
如果该视图当前不可见,则由UIViewController调用以响应内存警告 - 这基本上是您想要知道的.
EDITED
在回答后续问题时:
正确.
这就是我的工作,它对我有用.
正确.didReceiveMemoryWarning
在UIViewController中的实现就是这样做的.如果你不覆盖didReceiveMemoryWarning
,那么将调用UIViewController中的基类实现 - 如果你覆盖它,显然你应该调用:
[super didReceiveMemoryWarning]