如何实现 didReceiveMemoryWarning?

Posted

技术标签:

【中文标题】如何实现 didReceiveMemoryWarning?【英文标题】:How to implement didReceiveMemoryWarning? 【发布时间】:2011-01-26 16:58:41 【问题描述】:

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

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

当我对这个问题进行一些谷歌搜索时,我发现在内存不足的情况下,操作系统会将 didReceiveMemoryWarning 发送到当前层次结构中的所有控制器,以便每个控制器都应该实现 didReceiveMemoryWarning 方法并将 iboutlet 设置为 nil当前不可见的视图。

我还在某处读到,如果该控制器的视图不可见,则将调用带有 nil 参数的方法 setView 并且如果有一些出口变量附加到视图,则删除时会出现问题他们。

因此,有了所有这些基础,通过实现 didReceiveMemoryWarningviewDidUnload 方法来处理 Iphone 引发的低级内存状况的最佳方法是什么。

如果可能,请给出适当的示例或链接以解决上述问题。

谢谢。

【问题讨论】:

***.com/questions/491075/… 【参考方案1】:

我发布的一个示例...我从某处复制的...它可能会给您一些想法...

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

【讨论】:

嘿 mihir 我有 iboutlets,我正在从 nib 文件加载我的视图,只需检查我的问题的评论。这是令人困惑的,因为视图不可见,然后它会调用 viewDidUnaload 那么我应该怎么做才能使 didReceiveMemoryWarning 或 viewDidUNload 或 setView 中的值无效??????? 但是对于每个视图都会有单独的 didReceiveMemoryWarning 函数,因此针对特定视图实现此方法...在 viewDidUnload 方法中使用相应的访问器方法将对象的值设置为 nil... 嗨,你确定 [super didReceiveMemoryWarning];释放对象后需要放 在 didReceiveWarning 中释放内存/资源只是答案的一半。你什么时候/在哪里重新创建它们?它是如何工作的?【参考方案2】:

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

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

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

【讨论】:

好的,我已经通过在我的 viewDidUnload 方法中将 outlet 设为 nil 来制定我的解决方案。【参考方案3】:

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 永远不会被调用。 但是当内存警告发生时,我们仍然需要释放我们的视图(包括子视图)。 像这样。

- (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]。导致如果视图未加载,此方法将自动加载视图。

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

【讨论】:

实际上你可能想检查if (![self isViewLoaded] || [self.view window] == nil)。无论哪种情况,您都想清理子视图和其他内容。【参考方案4】:

您可以决定在didReceiveMemoryWarning 中做什么。操作系统告诉您内存不足,您需要尽快释放内存。这个想法是你应该释放所有缓存的数据,卸载不可见的视图,等等。细节是特定于应用程序的。

【讨论】:

【参考方案5】:

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

【讨论】:

这个页面上有一小段“内存警告”:developer.apple.com/iphone/library/documentation/Cocoa/… 这几天没有找到任何其他链接而不是那个【参考方案6】:

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

一些示例(例如 TableViewSuite)甚至可以做其他事情 ;-)

【讨论】:

以上是关于如何实现 didReceiveMemoryWarning?的主要内容,如果未能解决你的问题,请参考以下文章

如何在OpenGL应用程序中响应didReceiveMemoryWarning

iOS:didReceiveMemoryWarning 的帮助:

didReceiveMemoryWarning、viewDidUnload 和 dealloc

iOS 6 中的 didReceiveMemoryWarning

应该将 viewDidUnload 中的哪些工作移至 didReceiveMemoryWarning?

当应用程序在后台时没有收到 didReceiveMemoryWarning