viewDidUnload 和 viewWillUnload 被废弃之后的内存警告处理
2013-09-05 20:18
281 查看
由于iOS6以上的UIKit不会在内存警告时自动释放视图,所以viewWillUnload和viewDidUnload将不再触发。
因此,在iOS6上,开发者需要负责内存警告时将不用到的视图释放。
WWDC2012的视频有提到,具体代码如下:
- (void)didReceiveMemoryWarning { if ([self.view window] == nil) { self.view = nil; self.otherSubView = nil; }}
由于[self view]会引发视图的加载所以上述代码还是有潜在风险的,假如视图控制器在创建之后,在还没有加载视图时收到内存警告,那上面的代码就会触发视图的加载(调用了[self view]引起),反而加大了内存占用。所以应该先判断一下视图是否已被加载。
如果注册的通知跟界面相关,可以考虑将注册放入viewWillAppear并在viewWillDisappear中反注册。
如果需要在视图加载时就注册,那就在viewDidLoad注册,dealloc和didReceiveMemoryWarning中根据视图是否加载过来进行反注册。
注意viewDidUnload和viewDidLoad不是成对调用的,所以即使是iOS5或者以下的版本也不能在viewDidUnload里面反注册。参见[iOS] ViewController的生命周期及其加载View的步骤。
综上所述,最佳实践的代码如下:
2013-6-4 更新
UIKit在内存警告时不会释放视图的原因是不需要再释放。iOS6以上,视图对象跟视图的渲染位图已经很好地分开了,当内存警告时,UIKit会尝试释放没有贴在window上的视图的NSBackingStore,backingStore是视图的渲染位图,最占内存的部分,而UIView和CALayer本身只占几十K内存,所以视图的释放意义不大,并且不释放的话,视图被重用时,其层次关系和设置等都不用重建。
最终代码如下:
因此,在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.}
相关文章推荐
- viewDidUnload 和 viewWillUnload 被废弃之后的内存警告处理
- viewDidUnload 和 viewWillUnload 被废弃之后的内存警告处理
- iosLearningDiary_viewDidUnload 和 viewWillUnload 被废弃之后的内存警告处理
- ios6.0内存警告的兼容处理 viewDidUnload 屏蔽
- UI 第三课 ⼀、自定义视图 二、视图控制器指定⾃自定义View 三、检测屏幕旋转 四、处理内存警告 五、容器视图控制器
- 用MapViewOfFile处理大文件-内存不足(转帖学习)
- ios6 处理内存警告
- Declaration of 'struct sockaddr_in' will not be visible outside of this function警告的处理
- iOS6.0以后App对内存警告的处理
- iOS响应内存警告-对App内存不足的处理
- 二、当应用接收到内存警告时应该怎么处理
- IOS6.0以后APP对内存警告的处理
- iOS6内存警告处理
- iOS 收到内存警告的处理过程
- 用MapViewOfFile处理大文件-内存不足
- ios内存警告处理
- 我的服务器内存慢之后的处理逻辑
- iOS 6.0不同版本内存警告的统一处理
- 05_1 检测屏幕的旋转 、处理内存警告
- ios系统 处理内存警告