zoukankan      html  css  js  c++  java
  • viewDidUnload 和 viewWillUnload 被废弃之后的内存警告处理

    由于iOS6以上的UIKit不会在内存警告时自动释放视图,所以viewWillUnload和viewDidUnload将不再触发。
    因此,在iOS6上,开发者需要负责内存警告时将不用到的视图释放。
    WWDC2012的视频有提到,具体代码如下:

    1 - (void)didReceiveMemoryWarning {  
    2      if ([self.view window] == nil) {  
    3           self.view = nil;  
    4           self.otherSubView = nil;  
    5      }  
    6 } 

    由于[self view]会引发视图的加载所以上述代码还是有潜在风险的,假如视图控制器在创建之后,在还没有加载视图时收到内存警告,那上面的代码就会触发视图的加载(调用了[self view]引起),反而加大了内存占用。所以应该先判断一下视图是否已被加载。

    1 - (void)didReceiveMemoryWarning {  
    2      if ([self isViewLoaded] && [self.view window] == nil) {  
    3           self.view = nil;  
    4           self.otherSubView = nil;  
    5      }  
    6 }  

    Notification 的注册和反注册以及Delegate的设置和置空

    如果注册的通知跟界面相关,可以考虑将注册放入viewWillAppear并在viewWillDisappear中反注册。
    如果需要在视图加载时就注册,那就在viewDidLoad注册,dealloc和didReceiveMemoryWarning中根据视图是否加载过来进行反注册。
    注意viewDidUnload和viewDidLoad不是成对调用的,所以即使是iOS5或者以下的版本也不能在viewDidUnload里面反注册。参见[iOS] ViewController的生命周期及其加载View的步骤。

    综上所述,最佳实践的代码如下:

     1 - (void)viewDidLoad  
     2 {  
     3      self.subView.delegate = self;  
     4      [[NSNotificationCenter defaultCenter] addObserver:self];  
     5      self.viewCreatedByCode = [[UIView alloc] init];  
     6 }  
     7   
     8 // 自定义函数viewUnloaded,其操作与viewDidLoad对称。  
     9 - (void)viewUnloaded  
    10 {  
    11      self.subView.delegate = nil;  
    12      [[NSNotificationCenter defaultCenter] removeObserver:self];  
    13      self.viewCreatedByCode = nil;  
    14 }  
    15   
    16   
    17 - (void)didReceiveMemoryWarning {  
    18      if ([self isViewLoaded] && [self.view window] == nil) {  
    19           self.view = nil; // 需要开发者手动释放控制器的视图。  
    20           self.viewCreatedByNib = nil;  // 在xib中创建的视图也要手动清空。  
    21           [self viewUnloaded]; // 视图已被卸载,调用viewDIdLoad的反操作。  
    22      }  
    23 }  
    24    
    25 - (void)dealloc  
    26 {  
    27      if ([self isViewLoaded]) {  
    28           [self viewUnloaded]; // 如果视图已被加载,说明viewDidLoad被调用过,所以调用viewDidLoad的反操作。  
    29      }  
    30 } 

    UIKit在内存警告时不会释放视图的原因是不需要再释放。iOS6以上,视图对象跟视图的渲染位图已经很好地分开了,当内存警告时,UIKit会尝试释放没有贴在window上的视图的NSBackingStore,backingStore是视图的渲染位图,最占内存的部分,而UIView和CALayer本身只占几十K内存,所以视图的释放意义不大,并且不释放的话,视图被重用时,其层次关系和设置等都不用重建。

    最终代码如下:

     1 - (void)viewDidLoad  
     2 {  
     3      self.subView.delegate = self;  
     4      [[NSNotificationCenter defaultCenter] addObserver:self];  
     5      self.viewCreatedByCode = [[UIView alloc] init];  
     6 }  
     7   
     8 // 自定义函数viewUnloaded,其操作与viewDidLoad对称。  
     9 - (void)viewUnloaded  
    10 {  
    11      self.subView.delegate = nil;  
    12      [[NSNotificationCenter defaultCenter] removeObserver:self];  
    13      self.viewCreatedByCode = nil;  
    14 }  
    15   
    16   
    17 - (void)didReceiveMemoryWarning {  
    18      if ([self isViewLoaded] && [self.view window] == nil) {  
    19           // 如果需要,释放占内存的数据。  
    20           // 注意此时不会释放view,所以之后访问self.view时不一定会触发viewDidLoad  
    21      }  
    22 }  
    23    
    24 - (void)dealloc  
    25 {  
    26      if ([self isViewLoaded]) {  
    27           [self viewUnloaded]; // 如果视图已被加载,说明viewDidLoad被调用过,所以调用viewDidLoad的反操作。  
    28      }  
    29 }  
  • 相关阅读:
    Python第二天 (数据类型,变量 )
    python第一天(安装运行python)
    Linux shell 整数运算 let [ ] (( )) expr以及 浮点数 bc用法(转)
    2018年3月大事件
    2018年2月大事件
    项目假设与制约因素
    调用微信红包接口,本地可以服务器不可以。 请求被中止: 未能创建 SSL/TLS 安全通道
    【转】AddMvcCore,AddControllers,AddControllersWithViews,AddRazorPages的区别
    sql server create table 给字段添加注释说明
    HttpContext.SignInAsync 失效(表面解决了问题,未深入到.net core 源码去找问题,记录一下,等有时间翻一下.net core 源码试试能不能找到根本原因)
  • 原文地址:https://www.cnblogs.com/PressII/p/3746116.html
Copyright © 2011-2022 走看看