`
啸笑天
  • 浏览: 3462222 次
  • 性别: Icon_minigender_1
  • 来自: China
社区版块
存档分类
最新评论

ios6 处理内存警告

 
阅读更多

     iPhone下每个app可用的内存是被限制的,如果一个app使用的内存超过20M,则系统会向该app发送Memory Warning消息。收到此消息后,app必须正确处理,否则可能出错或者出现内存泄露。

     app收到Memory Warning后会调用:UIApplication::didReceiveMemoryWarning -> UIApplicationDelegate::applicationDidReceiveMemoryWarning,然后调用当前所有的viewController进行处理。因此处理的主要工作是在viewController

    当我们的程序在第一次收到内存不足警告时,应该释放一些不用的资源,以节省部分内存。否则,当内存不足情形依然存在,iOS再次向我们程序发出内存不足的警告时,我们的程序将会被iOS kill掉。

 

    iOSUIViewController 类给我们提供了处理内存不足的接口。在iOS 3.0 之前,当系统的内存不足时,UIViewControllerdidReceiveMemoryWarining 方法会被调用,我们可以在didReceiveMemoryWarining 方法里释放掉部分暂时不用的资源。

    iOS3.0 开始,UIViewController增加了viewDidUnload方法。该方法和viewDIdLoad相配对。当系统内存不足时,首先UIViewControllerdidReceiveMemoryWarining 方法会被调用,而didReceiveMemoryWarining 会判断当前ViewControllerview是否显示在window上,如果没有显示在window上,则didReceiveMemoryWarining 会自动将viewcontroller view以及其所有子view全部销毁,然后调用viewcontrollerviewdidunload方法。如果当前UIViewControllerview显示在window上,则不销毁该viewcontrollerview,当然,viewDidunload也不会被调用了。但是到了ios6.0之后,这里又有所变化,ios6.0内存警告的viewDidUnload 被屏蔽,即又回到了ios3.0的时期的内存管理方式。   


    iOS3-iOS5.0
以前版本收到内存警告:
调用didReceiveMemoryWarning内调用superdidReceiveMemoryWarning会将controllerview进行释放。所以我们不能将controllerview再次释放。
处理方法:
        

 -(void)didReceiveMemoryWarning
        {
                 [super didReceiveMemoryWarning];//如没有显示在window上,会自动将self.view释放。
                 // ios6.0以前,不用在此做处理,self.view释放之后,会调用下面的viewDidUnload函数,在viewDidUnload函数中做处理就可以了。
        }
        -(void)viewDidUnload
        {
               // Release any retained subviews of the main view.不包含self.view
               //处理一些内存和资源问题。
                [super viewDidUnload];
              
        }
 

 

    iOS6.0及以上版本的内存警告:
调用didReceiveMemoryWarning内调用superdidReceiveMemoryWarning只是释放controllerresouse,不会释放view
处理方法:
    -(void)didReceiveMemoryWarning
    {
            [super didReceiveMemoryWarning];//
即使没有显示在window上,也不会自动的将self.view释放。
            // Add code to clean up any of your own resources that are no longer necessary.

            //
此处做兼容处理需要加上ios6.0的宏开关,保证是在6.0下使用的,6.0以前屏蔽以下代码,否则会在下面使用self.view时自动加载viewDidUnLoad

            if ([[UIDevice currentDevice].systemVersion floatValue] >= 6.0) {

             //需要注意的是self.isViewLoaded是必不可少的,其他方式访问视图会导致它加载 ,在WWDC视频也忽视这一点

             if (self.isViewLoaded && !self.view.window)// 是否是正在使用的视图
             {
                   // Add code to preserve data stored in the views that might be
                   // needed later.
        
                   // Add code to clean up other strong references to the view in
                   // the view hierarchy.
                   self.view = nil;//
目的是再次进入时能够重新加载调用viewDidLoad函数。
             }

           }
    }

 

但是似乎这么写相对于以前并不省事。最终我们找到一篇文章,文章中说其实并不值得回收这部分的内存,原因如下:

1. UIViewUIResponder的子类,而UIResponder有一个CALayer的成员变量,CALayer是具体用于将自己画到屏幕上的。

2. CALayer是一个bitmap图象的包装类,当UIView调用自身的drawRect时,CALayer才会创建这个bitmap图象类。

3. 具体占内存的其实是一个bitmap图象类,CALayer只占48bytes, UIView只占96bytes。而一个iPad的全屏UIViewbitmap类会占到12M的大小!

4.iOS6时,当系统发出MemoryWarning时,系统会自动回收bitmap类。但是不回收UIViewCALayer类。这样即回收了大部分内存,又能在需要bitmap类时,根据CALayer类重建。

    所以iOS6这么做的意思是:我们根本没有必要为了几十byte而费力回收内存。

 

--------------------------切糕分割线--------------

PS:

1、关于这个的官方文档:https://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html

2、zon2012貌似都没有ios6的这个兼容(其实view是没问题的,关键是资源)

 

分享到:
评论
1 楼 啸笑天 2013-05-14  
移动设备终端的内存极为有限,应用程序必须做好low-memory处理工作,才能避免程序因内存使用过大而崩溃。

low-memory 处理思路
通常一个应用程序会包含多个view controllers,当从view跳转到另一个view时,之前的view只是不可见状态,并不会立即被清理掉,而是保存在内存中,以便下一次的快速显现。但是如果应用程序接收到系统发出的low-memory warning,我们就不得不把当前不可见状态下的views清理掉,腾出更多的可使用内存;当前可见的view controller也要合理释放掉一些缓存数据,图片资源和一些不是正在使用的资源,以避免应用程序崩溃。

思路是这样,具体的实施根据系统版本不同而略有差异,本文将详细说明一下iOS 5与iOS 6的low-memory处理。

iOS 5 的处理
在iOS 6 之前,如果应用程序接收到了low-memory警告,当前不可见的view controllers会接收到viewDidUnload消息(也可以理解为自动调用viewDidUnload方法),所以我们需要在 viewDidUnload 方法中释放掉所有 outlets ,以及可再次创建的资源。当前可见的view controller 通过didReceiveMemoryWarning 合理释放资源,具体见代码注释。

举一个简单的例子,有这样一个view controller:
@interface MyViewController : UIViewController { 
    NSArray *dataArray; 

@property (nonatomic, strong) IBOutlet UITableView *tableView; 
@end

对应的处理则为:
#pragma mark -
#pragma mark Memory management

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
   
    // Relinquish ownership any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
    // Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
    // For example: self.myOutlet = nil;
    self.tableView = nil;
    dataArray = nil;
   
    [super viewDidUnload];
}

iOS 6 的处理
iOS 6 废弃了viewDidUnload方法,这就意味着一切需要我们自己在didReceiveMemoryWarning中操作。
具体应该怎么做呢?

1.将 outlets 置为 weak
当view dealloc时,没有人握着任何一个指向subviews的强引用,那么subviews实例变量将会自动置空。
@property (nonatomic, weak) IBOutlet UITableView *tableView;

2.在didReceiveMemoryWarning中将缓存数据置空
#pragma mark -  
#pragma mark Memory management  
 
 
- (void)didReceiveMemoryWarning 

    [super didReceiveMemoryWarning]; 
    // Dispose of any resources that can be recreated.  
    dataArray = nil; 
}
不要忘记一点,每当tableview reload 的时候,需要判断一下 dataArray ,若为空则重新创建。

兼容iOS 5 与 iOS 6
好吧,重点来了,倘若希望程序兼容iOS 5 与 iOS 6怎么办呢? 这里有一个小技巧,我们需要对didReceiveMemoryWarning 做一些手脚:
#pragma mark -
#pragma mark Memory management

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

判断一下view是否是window的一部分,如果不是,那么可以放心的将self.view 置为空,以换取更多可用内存。

这样会是什么现象呢?假如,从view controller A 跳转到 view controller B ,然后模拟low-memory警告,此时,view controller A 将会执行self.view = nil ; 当我们从 B 退回 A 时, A 会重新调用一次 viewDidLoad ,此时数据全部重新创建,简单兼容无压力~~

Note:
如果你好奇Apple为什么废弃viewDidUnload,可以看看Apple 的解释:
Apple deprecated viewDidUnload for a good reason. The memory savings from setting a few outlets to nil just weren’t worth it and added a lot of complexity for little benefit. For iOS 6+ apps, you can simply forget about view unloading and only implement didReceiveMemoryWarning if the view controller can let go of cached data that you can recreate on demand later.

相关推荐

    解析iOS内存不足时的警告以及处理过程

    内存警告 ios下每个app可用的内存是被限制的,如果一个app使用的内存超过了这个阀值,则系统会向该app发送Memory Warning消息。收到消息后,app必须尽可能多的释放一些不必要的内存,否则OS会关闭app。 几种内存警告...

    ios程序 内存优化记录LOG日志-20130112

    在iOS应用开发中,内存管理是一项至关重要的任务,特别是在iPad这样的资源有限的设备上。针对“ios程序 内存优化记录LOG日志-20130112”这个主题,我们可以深入探讨如何通过分析日志来识别并解决内存问题。 首先,...

    SDWebImage内存警告修复版

    然而,在处理大图时,即使SDWebImage原版设计有自动释放内存的机制,仍有可能因为内存管理不当导致内存警告。针对这个问题,"SDWebImage内存警告修复版"进行了优化,解决了可能导致内存峰值过高或内存泄漏的问题。 ...

    ios 网页视图与警告视图u

    在iOS开发中,网页视图(WebView)和警告视图(Alert View)是两种非常重要的UI组件,它们分别用于展示网络内容和与用户进行交互。接下来,我们将详细探讨这两个概念及其在实际应用中的使用。 首先,让我们来看看...

    iOS 6 应用开发实战 Demo

    最后,为了确保良好的性能和用户体验,开发者可能运用了内存管理和优化技巧,比如避免内存泄漏,使用懒加载策略,以及遵循苹果的内存警告处理建议。 尽管缺少最后一章的代码,MyDiaryDemo依然提供了丰富的学习材料...

    IOS官方开发手册

    手册会详细阐述一个iOS应用从启动到运行再到退出的过程,以及如何处理屏幕旋转、内存警告等事件。此外,iOS支持多种后台模式,如后台音频、后台定位和后台刷新等,开发者需了解何时及如何使用这些模式。 网络编程是...

    iOS调试工具AllYourMemoriesAreBelong2iOS.zip

    AllYourMemoriesAreBelong2iOS 是一个方便的调试工具,其集成在 iOS 项目中,让开发者在调试过程中可以通过按动 iOS 物理设备的音量键来模拟内存警告通知的产生。该库由 @开源中国真理部部长 使用 Objective-C 语言...

    iOS内存暴增问题追查与使用陷阱.docx编程资料

    当设备内存不足时,iOS系统会向应用程序发送低内存警告。此时开发者应该采取以下措施: 1. **释放非关键资源** - 释放任何非必需的内存资源,如缓存图片或不必要的对象。 2. **优化内存使用** - 审查代码逻辑,...

    ios 多视图切换

    8. **内存警告和应用挂起**:除了`didReceiveMemoryWarning`,当接收到全局的内存警告时,所有视图控制器都应检查并释放资源。同时,应用挂起时(如进入后台),视图控制器需要保存状态以便恢复。 总的来说,iOS多...

    iOS 时分秒计数器

    4. **处理内存警告**: 当系统资源紧张时,可能会发送内存警告。为了防止应用被强制退出,我们应在收到内存警告时暂停计时器并释放可能占用的资源。 5. **手写识别**: 压缩包中的"秒表计时器_手写"可能指的是...

    iOS-网络图片加载demo

    项目可能包含了对内存警告的响应,以及在必要时清理缓存的逻辑。 通过研究这个项目,开发者可以深入理解如何在iOS应用中高效地加载网络图片,同时也能学习到如何利用缓存和异步操作提升用户体验。这是一个很好的...

    4-【理解】内存管理的原则.zip

    了解如何监听并妥善处理内存警告是提高应用性能的关键。 6. 性能优化:合理管理内存不仅可以避免程序崩溃,还能提升用户体验。了解内存分配和释放的时间开销,以及适时使用`autoreleasepool`,可以帮助优化代码。 ...

    Beginning iOS 5 Development Exploring the iOS SDK

    这包括了解应用程序如何启动、暂停、恢复和终止,以及如何处理内存警告。同时,事件驱动模型也是iOS开发的重要概念,例如触摸事件、手势识别和多任务处理。 UIKit框架是iOS开发中的基石,它包含了一系列用于构建...

    25条提高iOSApp性能的建议和技巧

    应用程序在内存不足时会收到内存警告通知,合理处理内存警告,可以避免应用被系统强制退出。 13. **重用大开销对象**: 对于那些创建成本高的对象,如图像处理对象,应当尽量重用而不是每次需要时都创建新实例。 ...

    iOSMemoryBudgetTest:尝试分配尽可能多的内存以使其崩溃的小型iOS应用程序。 之后,您可以再次运行该应用程序,以查看崩溃需要多少内存以及何时发生所有内存警告

    这个小型应用的主要目标是帮助开发者理解iOS设备在面临内存压力时的行为,特别是当内存分配接近设备限制时,如何触发内存警告以及最终导致应用崩溃。 首先,我们来深入了解一下Objective-C。Objective-C是Apple的...

    ios pdf阅读器

    另外,确保应用遵循iOS的内存警告机制,以便在内存紧张时及时释放资源。 7. **安全性与隐私** 使用UIWebView或WKWebView加载PDF时,应考虑文件的安全性。如果PDF包含敏感信息,需要确保只有授权的用户才能访问。...

    kache, iOS缓存控件,支持哈希,队列和时间池.zip

    线程安全确保了多线程环境下kache的正确操作,而内存警告响应机制则可以帮助应用在内存紧张时及时释放缓存,防止应用被系统强制关闭。 在实际项目中,开发者可以根据需求选择使用kache的部分或全部功能。例如,在...

    iOS 性能优化

    11. **处理内存警告**:监听并适当地响应内存警告,及时释放内存,防止应用被系统杀死。 12. **重用大开销的对象**:对于创建成本高的对象,例如数据库连接,可以复用以节省资源。 13. **使用SpriteSheets**:对于...

Global site tag (gtag.js) - Google Analytics