2009-01-29 72 views
5

背景iPhone发展 - 模拟内存警告

我有一个标签栏的应用程序。每个选项卡都包含导航控制器,允许用户从一个视图切换到另一个视图,以显示数据的深入信息(每个视图由视图控制器处理,每个视图控制器类具有didReceiveMemoryWarning方法)。通过从Web服务提取数据来填充列表。

问题

当我使用“硬件>模拟内存警告” iPhone模拟器的选项,该didReceiveMemoryWarning方法被称为我的所有视图控制器 - 即使该用户正在观看一个。我不想清除活动视图控制器正在使用的任何内容。我怎样才能做到这一点?

哪些方法应该有实现来重新加载数据后,数据被释放,因为内存警告? (我看到了含有表视图调用viewDidLoad方法,当用户回来这种看法,但如果视图包含(说UIWebView的),那么viewDidLoad方法不叫视图控制器类。这是为什么?)

编辑(星期五2009年1月30日 - 下午3点10分)

(注:我使用界面生成器创建视图和loadView方法被注释掉)

所以,当一个视图控制器接收到内存警告消息,这些是执行的步骤:

  1. 调用下面的方法:

    - (void)didReceiveMemoryWarning { 
        [super didReceiveMemoryWarning]; 
    } 
    
  2. 呼叫到[super didReceiveMemoryWarning]的结果,[self setView:nil]就会自动叫什么名字?

  3. 如果应该清除任何资源,则应该覆盖setView方法以清除本地资源。如果视图当前处于活动状态(默认),则不调用[self setView:nil]。对? - 我很好奇哪种方法需要这个决定,以及如何?

您能否确认一下。另外,我收到了一个错误,下面是这个方法,但是在中加入myObject = nil后发现dealloc控制器类的方法修复了这个问题。谢谢。

回答

12

这是一个老问题,但我没有看到一个合适的回答,所以这里有云:

当接收到一个内存警告,-didReceiveMemoryWarning被称为在所有视图控制器,无论是“当前”一个或不。视图控制器只是在监听内存警告事件广播。

如果在内存警告时没有使用视图控制器的视图,控制器将通过将该属性设置为nil来卸载它。它如何知道该视图是否被使用?由该视图的-superview属性。如果view.superview为零,则该视图不是任何树的一部分,并且可以安全卸载。

一旦发生这种情况,控制器的-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. 
} 
8

我做我的清理是这样的:

-(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

在回答如下窗口:

  1. 正确的。
  2. 这就是我所做的,它适用于我。
  3. 正确。在UIViewController中执行didReceiveMemoryWarning是什么。如果不重写didReceiveMemoryWarning,那么在UIViewController中基类的实现将被称为 - 如果你重写它,很明显你应该叫:

    [super didReceiveMemoryWarning] 
    
+0

即使我不重写didReceiveMemoryWarning方法,我的观点被清除。这是为什么? – Mustafa 2009-01-30 05:04:01

1

至于视图管理和内存警告:

UIKit不仅允许从视图控制器返回导航,还允许从现有视图导航到其他视图控制器。 在这种情况下,将分配一个新的UIViewController,然后将其加载到视图中。 旧的视图控制器将离开屏幕并变为非活动状态,但仍拥有许多对象 - 一些位于自定义属性和变量中,另一些位于视图属性/层次结构中。 对于其视图对象,新的可见视图控制器也是如此。

由于移动设备的内存量有限,拥有这两组对象(一个位于屏幕外视图控制器和另一个位于屏幕视图控制器中)可能太多,无法处理。 如果UIKit认为它是必要的,它可以回收一些关闭屏幕视图控制器的内存,但不会显示; UIKit知道哪个视图控制器在屏幕上,哪个是屏幕外的,毕竟它是管理它们的人(当你拨打presentModalViewController:animated:dismissModalViewControllerAnimated:时)。 因此,每次感觉到压力时,UIKit会生成一条内存警告,它会从视图层次结构中卸载并释放离屏视图,然后调用您的自定义viewDidUnload方法,以便为属性和变量执行相同的操作。 UIKit自动发布self.view,允许我们手动发布我们的viewDidUnload代码中的变量和属性。 它对所有离屏视图控制器都这样。

当系统内存不足时,会触发didReceiveMemoryWarning。 当屏幕出现内存警告时,屏幕视图将被回收并释放,但屏幕视图不会被释放 - 它是可见的并且是需要的。 如果您的班级拥有大量内存(如缓存,图像等),则应该清除didReceiveMemoryWarning,即使它们在屏幕上;否则,您的应用可能会因为系统资源过剩而终止。 您需要重写此方法以确保清理内存;只记得你叫[super didReceiveMemoryWarning];

一个更复杂的解释,请访问:http://myok12.wordpress.com/2010/11/30/custom-uiviewcontrollers-their-views-and-their-memory-management/

0

幸运的是,模拟器有一个方便的功能,可以让您将低内存情况加入测试。把一些的NSLog()语句都viewDidLoad中和didReceiveMemoryWarning,像这样: 

- (void)viewDidLoad { 
    NSLog(@"viewDidLoad"); 
    ... 
} 

- (void)didReceiveMemoryWarning { 
    NSLog(@"didReceiveMemoryWarning"); 
}