如何实现didReceiveMemoryWarning?

时间:2010-03-12 05:41:28

标签: iphone memory-management

我开发了一个简单的位置感知iPhone应用程序,除了在手机内存不足的情况下,它在功能上非常符合我们的期望。

在手机内存不足的情况下,我的应用程序只会崩溃,如果我通过释放一些空间来增加手机内存,它会再次开始正常运行而不会发生任何崩溃。

当我在搜索问题时,我发现在低内存条件下操作系统会将didReceiveMemoryWarning发送到当前层次结构中的所有控制器,这样每个控制器都应该实现didReceiveMemoryWarning方法,并将iboutlet设置为nil目前看不到的视图。

我还读过一些地方,如果该控制器的视图不可见,将调用带有nil参数的方法 setView ,如果视图中附加了一些插件变量,则删除时会出现问题它们。

因此,对于所有这些基金,通过实施 didReceiveMemoryWarning viewDidUnload 方法,最好能够处理由Iphone引发的低级别内存条件。

如果可能,请提供正确的示例或链接以解决上述问题。

感谢。

6 个答案:

答案 0 :(得分:21)

我发帖的一个例子......我从某个地方复制了......它可能会给你一些想法......

- (void)didReceiveMemoryWarning {

    // Release anything that's not essential, such as cached data (meaning
    // instance variables, and what else...?)

    // Obviously can't access local variables such as defined in method
    // loadView, so can't release them here We can set some instance variables
    // as nil, rather than call the release method on them, if we have defined
    // setters that retain nil and release their old values (such as through use
    // of @synthesize). This can be a better approach than using the release
    // method, because this prevents a variable from pointing to random remnant
    // data.  Note in contrast, that setting a variable directly (using "=" and
    // not using the setter), would result in a memory leak.
    self.myStringB = nil;
    self.myStringD = nil;
    [myStringA release];// No setter defined - must release it this way
    [myStringC release];// No setter defined - must release it this way

    /* 3. MUST CONFIRM: NOT necessary to release outlets here - See override of
       setView instead.
    self.labelA = nil;
    self.imageViewA = nil;
    self.subViewA = nil;
     */
    // Releases the view if it doesn't have a superview
    [super didReceiveMemoryWarning];
}

答案 1 :(得分:15)

内存警告向您发出信号,告知您应该处置任何非绝对关键的资源。大多数控制器将挂在数据缓存,中间数据或其他零碎件上,通常是为了节省重新计算。当他们收到内存警告时,他们应该开始冲洗他们不需要的任何东西以便操作。

如何确定什么是“关键”取决于您的应用程序的设计。例如,OpenGL游戏可以确定当前在屏幕上的纹理是有价值的并且是不可见的齐平纹理,或者是在当前游戏区域的边界之外的级别数据。具有大量会话日志的应用程序(如IRC客户端)可能会将它们从内存中清除并刷新到磁盘上。

正如您所观察到的,警告会发送到您的层次结构中的每个控制器,因此每个部分都需要单独确定哪些数据构成“对操作至关重要”以及什么构成“可消耗”。如果你已经对它们进行了优化并且仍然没有内存警告,那么很遗憾是时候重新审视你的核心应用程序设计,因为你超出了硬件的限制。

答案 2 :(得分:15)

在iOS 5及更早版本上。

当控制器收到内存警告时,将调用didReceiveMemoryWarning。此时,如果控制器的视图不在视图层次结构中,则视图将设置为nil,并且将自动调用viewDidUnload。因此,我们必须在viewDidUnload中执行的操作是释放在viewDidLoad中创建的子视图或从Nib创建的子视图。像这样:

- (void)viewDidUnload
{
    self.subView = nil;
    self.subViewFromNib = nil;
}

- (void)didReceiveMemoryWarning
{
    self.someDataCanBeRecreatedEasily = nil;
    [super didReceiveMemoryWarning];
}

在iOS6上。

接收到内存警告时,控制器不会自动释放视图。所以viewDidUnload永远不会被调用。 但是当发生memry警告时,我们仍然需要释放我们的视图(包括子视图)。 像这样。

- (void)didReceiveMemoryWarning
{
    if ([self isViewLoaded] && [self.view window] == nil) {
        self.view = nil;
        self.subView = nil;
        self.subViewFromNib = nil;
    }
    self.someDataCanBeRecreatedEasily = nil;
    [super didReceiveMemoryWarning];
}

请注意,在我们知道加载视图之前,我们不会调用[self view]。因为如果未加载视图,此方法将自动加载视图。

请注意,我们可以在视图未添加到窗口时释放视图。

答案 3 :(得分:5)

由您决定在didReceiveMemoryWarning中做什么。操作系统告诉你内存很低,你需要尽可能快地释放内存。我们的想法是,您应该释放任何缓存的数据,卸载不可见的视图等。详细信息是特定于应用程序的。

答案 4 :(得分:4)

您还可以在didReceiveMemoryWarning中释放您为类中的静态变量分配的内存。因为一旦分配了静态变量的内存,它就不会在应用程序运行期间被释放。

答案 5 :(得分:2)

令我惊讶的是,官方iPhone示例中只有少数应用程序实现didReciveMemoryWarning。您可以使用iPhoneCoreDataRecipes示例作为参考。

有些样本(例如TableViewSuite)甚至做了别的事情; - )