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

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

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

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

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

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

Java代码                          

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

iOS6.0及以上版本的内存警告:
调用didReceiveMemoryWarning内调用super的didReceiveMemoryWarning调只是释放controller的resouse,不会释放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. UIView是UIResponder的子类,而UIResponder有一个CALayer的成员变量,CALayer是具体用于将自己画到屏幕上的。

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

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

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

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

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

PS:

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

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

分享到:

xcode4.5(iOS 6)开发与之前的差异 | IOS发送Email的方法

评论

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.

ios6 处理内存警告的更多相关文章

  1. UIViewController的生命周期及iOS程序执行顺序 和ios6 处理内存警告

    当一个视图控制器被创建,并在屏幕上显示的时候. 代码的执行顺序1. alloc                                   创建对象,分配空间2.init (initWithN ...

  2. ios系统 处理内存警告

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

  3. ios 处理内存警告

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

  4. ios6如何处理内存,分别为前警告后

    这里有一篇文章.非常具体地说明了ios6前后是怎样处理内存警告的: 来自唐巧的技术博客:http://blog.devtang.com/blog/2013/05/18/goodbye-viewdidu ...

  5. iOS6后的内存警告处理

    [iOS6后的内存警告处理] The memory used by a view to draw itself onscreen is potentially quite large. However ...

  6. ##DAY3 自定义视图、视图控制器、视图控制器指定视图、loadView、 viewDidLoad、MVC、屏幕旋转、内存警告

    ##DAY3 自定义视图.视图控制器.视图控制器指定视图.loadView. viewDidLoad.MVC.屏幕旋转.内存警告 #pragma mark ———————自定义视图的步骤 —————— ...

  7. 解读AppIcon图标设置置信息和App内存警告临界值

    前面有同学问到了iOS内存警告临界值和工程项目里AppIcon的一些配置信息,相信对刚入行的同学来说,可能都会碰到类似的问题,记录一下供后来者查询. 1.先简单说下AppIcon的图标的配置信息 1) ...

  8. 控制器View的加载和内存警告流程图

    控制器View的加载 内存警告

  9. 解决MWPhotoBrowser中的SDWebImage加载大图导致的内存警告问题

    下面两种现象,用同一种方法解决 1.解决MWPhotoBrowser中的SDWebImage加载大图导致的内存警告问题 2.突然有一天首页访问图片很慢,至少隔20多秒所有图片才会出来.(解析:app使 ...

随机推荐

  1. [书目20131223]Android、iPhone、Windows Phone手机网页及网站设计:最佳实践与设计精粹 - 张亚飞

    目录 第I篇 手机版专用网站设计和开发入门篇 第1章 准备创作环境和测试环境 3 1.1 使用Mobile Safari测试网页 4 1.1.1 iOS Simulator安装 5 1.1.2 使用M ...

  2. 转: 数字证书原理 https 完整过程解析

    点评: 讲的非常的详细与全面,值得一看. 转: http://www.cnblogs.com/JeffreySun/archive/2010/06/24/1627247.html 文中首先解释了加密解 ...

  3. IDG合伙人李丰:O2O中的C2C蕴藏巨大商机

    [ 亿欧导读 ] IDG合伙人李丰表示,每个新趋势出现,都是在解决上一轮行业革新时没有解决好的市场需求.而O2O中的C2C将会出现巨大商机的原因在于移动互联网的出现创造了新的交互方式,可以更快速的匹配 ...

  4. 浅谈实现placeholder效果的几种方案

    placeholder是html5<input>的一个属性,它提供可描述输入字段预期值的提示信息(hint), 该提示会在输入字段为空时显示.高端浏览器支持此属性(ie10/11在获得焦点 ...

  5. Part 1 What is SSMS?

    note that,SSMS is a client tool and not the server by itself,it is a developer machines connects to ...

  6. swift-自定义无限轮播图

    一  前言 1.之前一直在用OC编程,最近才开始接触使用swift就发现使用OC越来越不习惯,感觉已经爱上了swift. 2.这个自定义轮播图只是对之前OC版本进行了翻译,欢迎指正. 3.我决定一步步 ...

  7. XtraGrid使用心得(折叠式主细档、分组统计)

    XtraGrid的关键类就是:GridControl和GridView.GridControl本身不显示数据,数据都是显示在GridView/CardView/XXXXView中.GridContro ...

  8. C#高效率导出Excel

    首先,需要引用excel的库: Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Exce ...

  9. javascript数据结构——写一个二叉搜索树

    二叉搜索树就是左侧子节点值比根节点值小,右侧子节点值比根节点值大的二叉树. 照着书敲了一遍. function BinarySearchTree(){ var Node = function(key) ...

  10. 关于js unshift() 与pop() 功能

    最近在研究如何精简贪吃蛇代码,网上许多大神已经将其精简到30行之内就可以搞定. 我尝试着学习并且研究是否能进一步精简的方式. 偶然间又重新温习了一遍pop()和unshift() 的功能.(之前有学过 ...