iOS的版本号已经到了6.0.1了, 这篇文章说60%的iPhone用户已经升级到了iOS6了。那我们的应用有没有做好相关的准备工作呢。
今天在调试代码的时候,用模拟器模拟内存警告,结果发现自己的ViewController竟然不响应viewDidUnload函数,尼玛,这可是个大问题。
查询文档,iOS升级到6.0以后,不再支持viewDidUnload了。官方文档的解释是系统会自动控制大的View所占用的内存,其他小的View所占用的内存是极其微小的,不值得为了省内存而去清理然后在重新创建。如果你需要在内存警告的时候释放业务数据或者做些其他的特定处理,你可以实现 didReceiveMemoryWarning 这个函数。苹果官方文档请猛击
总结下:iOS6 之前:
viewDidUnload 和 didReceiveMemoryWarning 都会被调用。
iOS6 及其后面的版本。
viewDidUnload 不会被调用 didReceiveMemoryWarning 依然被调用。系统会自动处理view相关的内存,我们不用担心。
苹果官方给出的解释了相关的方案总是看起来十分美好的,但是现实往往是残酷。
1.我们的工程是ARC的。
2.我们会在viewController里面持有大量子view的成员变量(strong)
3.我们实现了大量的viewDidUnload函数来释放 (2)里面持有的那个子view。
让我们看看我们的代码到了iOS6以后会发生什么事情。因为所有的子view都是strong持有的,这样会导致,及时系统内存警告导致了view的回收,他们也不会被真正的释放。于是乎,我们的程序可能就在后台被系统频繁的杀死。
分析到这里,解决方案也就很清楚了,我就不罗嗦了。贴段Apple给的解决方案代码。
一个App 有 3个 tab,A 、B、C。(都从viewController继承,并且都实现了didReceiveMemoryWarning)。当程序启动的时候,默认显示tab A,这个时候,A 的 viewDidload被调用,并且加载数据显示给用户。然后我们切换到 tab B,B会重复A的加载过程。
这时候系统产生了一个内存警告,A、B、C 3个对象都会受到警告。
A对象:因为它已经不在当前UI显示了,所以满足[self.view window] == nil,相关view被释放。
B对象:正在显示,所有didReceiveMemoryWarning什么也不会干。
C对象:最悲惨,从来没有显示过,viewDidload从来没调用过,也没有显示过。然后有个self.view .这句的调用会导致一个结果,就是C对象的viewDidload会被调用一次,于是他的逻辑就是释放前先创建一次,然后再把自己释放,是不是很悲剧。(所以apple给的方案也不一定完美靠谱)
到这里故事也讲了,最后说说,在iOS6 及其以后,我们应该怎么处理这个问题。
1.不要把 subView 当成成员变量来持有。使用tag来操作。(其实不管在哪个版本最后都这么做)
2.不需要实现viewDidUnload,由系统自己来控制相关的内存释放
3.在需要的时候实现didReceiveMemoryWarning来释放一些业务数据减少内存的占用,不要操作UIView。
也许有错误,欢迎大家指正交流