如何实现didReceiveMemoryWarning?

har*_*alb 49 iphone memory-management

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

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

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

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

因此,对于所有这些基金,通过实现didReceiveMemoryWarningviewDidUnload方法处理Iphone引发的低级内存条件是最好的 .

如果可能,请提供适当的示例或链接以解决上述问题.

谢谢.

Mih*_*hta 21

我发布的一个例子......我从somwhere复制过......它可能会给你一些想法......

- (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];
}
Run Code Online (Sandbox Code Playgroud)

  • 释放didReceiveWarning中的内存/资源只是答案的一半.什么时候/在哪里重温它们?这是如何运作的? (3认同)

Dan*_*ory 15

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

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

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


wih*_*ing 15

在iOS 5及更早版本.

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

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

- (void)didReceiveMemoryWarning
{
    self.someDataCanBeRecreatedEasily = nil;
    [super didReceiveMemoryWarning];
}
Run Code Online (Sandbox Code Playgroud)

在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];
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 实际上你可能想检查“if (![self isViewLoaded] || [self.view window] == nil)”。无论哪种情况,您都需要清理子视图和其他内容。 (2认同)

ric*_*chb 5

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