viewDidUnload 和 viewWillUnload 被废弃之后的内存警告处理

本文详细介绍了在iOS6及以上版本中UIKit行为的变化,特别是针对内存警告时视图管理的新策略。提供了如何手动管理视图释放和通知注册的最佳实践代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

 



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


 

- (void)didReceiveMemoryWarning { if ([self.view window] == nil) { self.view = nil; self.otherSubView = nil; }}

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

 



[plain] view plaincopyprint?

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


 

- (void)didReceiveMemoryWarning {
     if ([self isViewLoaded] && [self.view window] == nil) {
          self.view = nil;
          self.otherSubView = nil;
     }
}
Notification 的注册和反注册以及Delegate的设置和置空

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

综上所述,最佳实践的代码如下:
 
 
 
[plain] view plaincopyprint?
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.}  

- (void)viewDidLoad
{
     self.subView.delegate = self;
     [[NSNotificationCenter defaultCenter] addObserver:self];
     self.viewCreatedByCode = [[UIView alloc] init];
}

// 自定义函数viewUnloaded,其操作与viewDidLoad对称。
- (void)viewUnloaded
{
     self.subView.delegate = nil;
     [[NSNotificationCenter defaultCenter] removeObserver:self];
     self.viewCreatedByCode = nil;
}


- (void)didReceiveMemoryWarning {
     if ([self isViewLoaded] && [self.view window] == nil) {
          self.view = nil; // 需要开发者手动释放控制器的视图。
          self.viewCreatedByNib = nil;  // 在xib中创建的视图也要手动清空。
          [self viewUnloaded]; // 视图已被卸载,调用viewDIdLoad的反操作。
     }
}
 
- (void)dealloc
{
     if ([self isViewLoaded]) {
          [self viewUnloaded]; // 如果视图已被加载,说明viewDidLoad被调用过,所以调用viewDidLoad的反操作。
     }
}


2013-6-4 更新

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

最终代码如下:





[plain] view plaincopyprint?
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.}  


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值