iOS 5与iOS 6的 low-memory 处理

iOS 5 与 iOS 6 的 low-memory 处理



移动设备终端的内存极为有限,应用程序必须做好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 ,此时数据全部重新创建,简单兼容无压力~~


UPDATE -  2013.5.21

1.评论中,一位仁兄提供了他的解决办法:

在 didReceiveMemoryWarning 方法中判断,如果当前version >= 6.f ,就使用performSelectorOnMainThread 调用 viewDidUnload ,可以复用为了兼容5写的 viewDidUnload 方法。


想法很好,但是我认为其实大可不必,因为在iOS6中,之前viewDidUnload实现的事情已经完全托管了,并不是没有做相关处理,不需要在手动调用viewDidUnload。


2.也有人不推荐使用本文提到的清self.view的这种懒人兼容方法,具体可看:再见,viewDidUnload方法

我认为,这的确是值得每个人思考的,也欢迎大家说说自己的想法。



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.





评论 32
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值