iOS View的生命周期详解

View的生命周期流程图

clipboard.png

方法详解

  • loadView:每次访问view时,就会调用self.view的get方法,在get方法中判断self.view==nil,不为nil就直接返回view,等于nil就去调用loadView方法。loadView方法会去判断有无指定storyBord/Xib文件,如果有就去加载storyBord/Xib描述的控制器view,如果没有则系统默认创建一个空的view,赋给self.view。loadView方法有可能被多次调用(每当访问self.view并且为nil时就会调用一次);
  • viewDidLoad:view加载完成时调用(在loadView方法执行后被调用),也有可能执行多次(self.view==nil且被访问时);
  • awakeFromNib:通过storyboard创建控制器加载了控制器以及控制器view的nib文件,此方法在initWithCoder调用之后被调用。而通过Xib创建控制器只加载了控制器view的nib文件,所以控制器的awakeFromNib方法不会被调用,控制器view以及它的子视图的awakeFromNib也会被调用。awakeFromNib 方法,是在将同一归档中的所有对象都读取并初始化完成后才会被调用的(详情),此时连线已经完成
  • viewWillAppear:view即将可见时调用
  • viewWillLayoutSubviews:view即将布局子视图时调用
  • viewDidLayoutSubviews:view完成子视图布局后调用
  • viewDidAppear:view已经显示后调用
  • viewWillDisappear:view即将消失、被覆盖或者隐藏时调用此方法
  • viewDidDisappear:view已经消失、被覆盖或者隐藏时调用此方法
  • didReceiveMemoryWarning:当收到内存警告时调用此方法
  • viewWillUnload:当内存过低时,需要释放一些不需要使用的视图时,即将释放时调用(iOS6以后被废弃)
  • viewDidUnload:当内存过低,释放了一些不需要的视图时调用(iOS6以后被废弃)

内存警告时view的处理机制

iOS6以前(不包括iOS6)当内存警告时,我们会在viewDidUnload中手动的回收ViewController中的子视图或者ViewController的view([self.view removeFromSuperView]; self.view = nil;),当view再次被访问到时,就会再次调用loadView方法,viewController的view以及其子视图都会被重建。
其中包含两个关键点:

  • 内存警告时,viewDidUnload一定会被调用;
  • loadView会被调用多次

iOS6以后苹果废弃了viewWillUnload和viewDidUnload方法,所以以前在viewDidUnload中处理内存警告的代码就需要移动到didReceiveMemoryWarning中。但如果你觉得这样就没有问题了,那就错了。iOS6以后苹果废弃了那两个方法的同时也添加了内部处理view的方式,具体的处理机制如下:

iOS6及以后,内存警告时系统会回收ViewController的View的CALayer里的BitMap(CABackingStore类型,它的内容是直接用于渲染到屏幕,它是View消耗内存的大户)。view和calayer占的内存极少, 数量级也就在byte和kbyte之间,所以系统只回收了BitMap,但是这里所谓的回收只是给BitMap占用的内存打了一个volatile标记表明这部分内存是可能随时被其它数据占用,平时没内存警告时正在使用的内存标记为In use,完全被释放回收的标记为Not in use。概括起来也就是说:iOS6及以后的内存警告时,系统会给用于渲染视图的数据(BitMap)内存打一个volatile, ViewController的View的架子结构并不会回收,当View再次被访问时,虽然View的架子结构会用重建,但触发drawRect来渲染界面时,如果view对应的BitMap数据内存没有被占用则会被View的drawRect方法直接渲染出来且内存被标记为in use,从而这块内存又可以独享了;如果已被其它数据占用,那么BitMap必须要重建。所以可以看到整个重建过程不再是由loadView来做的,它是通过对view的访问来触发的。但是,请注意, 如果说在iOS6及以后ViewController的loadView方法只会被调用一次,这种说法是不完全准确的。因为:如果在didReceiveMemoryWarning里把ViewController的View也回收了([self.view removeFromSuperview];self.view = nil;),那么当再次有对View访问时,loadView会被调用以进行完全最彻底的重建(想想也是,ViewController的View都没了,不调loadView来重建那怎么办呢)。

iOS6这种的设计的优点:

  • 视图结构和视图数据的分离;
  • 内存警告后系统只回收的是内存大户视图数据,但是回收不是完全的清掉,而只是做个标记,这样既做到减小了每次重建BitMap 的成本,同时也把这部分内存开放出去可以随时被别的数据占用;
  • 重建时,充其量是重建BitMap(没被占用时是直接用不用重建);

参考文章
《iOS6+应该怎样覆盖didReceiveMemoryWarning》
《再见,viewDidUnload方法》
《loadView、viewDidLoad及viewDidUnload的关系》
《慎用 awakeFromNib 进行初始化》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值