出自:http://blog.csdn.net/yiyaaixuexi/article/details/8891923

移动设备终端的内存极为有限,应用程序必须做好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:

 

 

  1. @interface MyViewController : UIViewController {  
  2.     NSArray *dataArray;  
  3. }  
  4. @property (nonatomic, strong) IBOutlet UITableView *tableView;  
  5. @end  

 

 

对应的处理则为:

  1. #pragma mark -  
  2. #pragma mark Memory management  
  3.   
  4.   
  5. - (void)didReceiveMemoryWarning {  
  6.     // Releases the view if it doesn't have a superview.  
  7.     [super didReceiveMemoryWarning];  
  8.       
  9.     // Relinquish ownership any cached data, images, etc that aren't in use.  
  10. }  
  11.   
  12.   
  13. - (void)viewDidUnload {  
  14.     // Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.  
  15.     // For example: self.myOutlet = nil;  
  16.     self.tableView = nil;  
  17.     dataArray = nil;  
  18.       
  19.     [super viewDidUnload];  
  20. }  






iOS 6 的处理

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

 

 

1.将 outlets 置为 weak
当view dealloc时,没有人握着任何一个指向subviews的强引用,那么subviews实例变量将会自动置空。

  1. @property (nonatomic, weak) IBOutlet UITableView *tableView;  



2.在didReceiveMemoryWarning中将缓存数据置空

  1. #pragma mark -  
  2. #pragma mark Memory management  
  3.   
  4.   
  5. - (void)didReceiveMemoryWarning  
  6. {  
  7.     [super didReceiveMemoryWarning];  
  8.     // Dispose of any resources that can be recreated.  
  9.     dataArray = nil;  
  10. }  



不要忘记一点,每当tableview reload 的时候,需要判断一下 dataArray ,若为空则重新创建。




兼容iOS 5 与 iOS 6


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


  1. #pragma mark -  
  2. #pragma mark Memory management  
  3.   
  4.   
  5. - (void)didReceiveMemoryWarning  
  6. {  
  7.     [super didReceiveMemoryWarning];  
  8.       
  9.     if ([self isViewLoaded] && self.view.window == nil) {  
  10.         self.view = nil;  
  11.     }  
  12.       
  13.     dataArray = nil;  
  14. }  



判断一下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.

posted on 2013-05-21 10:21  知识天地  阅读(240)  评论(0编辑  收藏  举报