viewController生命周期学习笔记

在这里插入图片描述

本文写的顺序即方法的执行顺序

loadView

  • loadView这个方法是用来创建viewController的view的,因此当viewController的view为nil的时候,或者当我们初始化视图的时候会调用这个方法。
  • 默认实现[super loadView].它会调用方法找寻nib文件来创建View,nib文件是视图化变成产生的文件,如果我们没有用“拖”的方法来写控件,那么它找不到xib文件会默认生成一个空白的view。
  • 如果我们用编程来写控件,则不需要调用[super loadView],根据我们的需求自己创建viewController的view。

viewDidLoad

这个方法是在加载viewController的view的时候便会调用(不管是“拖”,还是“写”),在这个方法里我们主要是写界面的初始化,添加一些控件之类的

viewDidUnload 和 didReceiveMemoryWarning

iOS设备的内存是极其有限的,如果应用程序占用的内存过多的话,系统就会对应用程序发出内存警告。UIViewController就会收到didReceiveMemoryWarning消息。didReceiveMemoryWarning方法的默认实现是:如果当前UIViewController的view不在应用程序的视图层次结构(View Hierarchy)中,即view的superview为nil的时候(这个view正在显示),就会将view释放,并且调用viewDidUnload方法,这个调用的时机是:

  • 当收到内存警告时,如果viewcontroller未显示(在后台),会执行didReceiveMemoryWarning -> viewDidUnLoad;如果viewcontroller当前正在显示(在前台),则只执行didReceiveMemoryWarning。
    viewDidUnload需要释放对象,但它不会释放viewController

viewWillLayoutSubviews 和 viewWillAppear

viewWillAppear先执行
viewWillLayoutSubviews 后执行

viewWillApper
  • 系统在载入所有数据后,将会在屏幕上显示视图,这时会先调用这个方法。通常我们会利用这个方法,对即将显示的视图做进一步的设置。例如,我们可以利用这个方法来设置设备不同方向时该如何显示。

  • 另外一方面,当APP有多个视图时,在视图间切换时,并不会再次载入viewDidLoad方法,所以如果在调入视图时,需要对数据做更新,就只能在这个方法内实现了。所以这个方法也非常常用。

viewWillLayoutSubviews

首先说一说layoutSubviews
它调用的时机:
之前写的有问题,已经删除,请移步下边看第二次修改

You should override this method only if the autoresizing behaviors of the subviews do not offer the behavior you want.
layoutSubviews, 当我们在某个类的内部调整子视图位置时,需要调用。
反过来的意思就是说:如果你想要在外部设置subviews的位置,就不要重写。

  • 一般我们把控件的frame写在LayoutSubViews里,在addSubViews的时候会调用一次LayoutSubViews,如果我们设置frame的话,它还会调用一次,为了避免重复我们将frame的设置写在LayoutSubViews里。

而viewWillLayoutSubviews在它之前执行,这俩兄弟一样,本身方法里不执行啥,得自己写,看一看官方文档

官方文档说明—When a view’s bounds change, the view adjusts the position of its subviews. Your view controller can override this method to make changes before the view lays out its subviews. The default implementation of this method does nothing.(当一个视图的边界发生变化,也就是调整其子视图的位置。你的视图控制器可以重写此方法在layoutSubViews之前生效以重新布局子视图。该方法的默认实现不执行任何操作。)
官方解释了它的用途

  • viewDidLayoutSubviews 也在LayoutSubViews之前执行
    LayoutSubViews在view里实现,viewWillLayoutSubviews在controller里实现

ViewDidAppear

有时候,由于一些特殊的原因,我们不能在viewWillApper方法里,对视图进行更新。那么可以重写这个方法,在这里对正在显示的视图进行进一步的设置。

viewWillDisappea 和 viewDidDisappear

1.视图变换时,当前视图在即将被移除、或者被覆盖时,会调用这个方法进行一些善后的处理和设置。

由于在IOS4之后,系统允许将APP在后台挂起,所以在按了Home键之后,系统并不会调用这个方法,因为就这个APP本身而言,APP显示的view,仍是挂起时候的view,所以并不会调用这个方法。
viewDidDisappear: 我们可以重写这个方法,对已经消失,或者被覆盖,或者已经隐藏了的视图做一些其他操作。

dealloc 和 viewDidUnload

当释放viewController的时候会调用dealloc,视图被销毁,此处需要对你在init和viewDidLoad中创建的对象进行释放
和viewDidUnload作用一样,调用时机不同

完整流程

完整的流程是:
loadView
viewDidLoad
viewWillappear
viewWillLayoutSubviews
ViewDidayoutSubviews
layoutSubviews
ViewDidAppear
viewWillDisappea
viewDidDisappear
dealloc
github里有生命周期演示和新版xcode手动布局演示
viewController生命周期

第一次修改

因为loadvView在创建controller的view时会为它设置frame,所以layoutSubview一定会执行,viewWillLayoutSubviews
ViewWillLayoutSubviews也会执行,之前以为前俩个默认会执行,原来是前面写过frame。
但是我有个问题,viewcontroller的layoutSubview在哪里重写。

第二次修改

关于开头给出的一张图,loadView和viewDidload死循环,在Xcode版本不同情况下,死循环也不同。
死循环:
如果重写loadView,程序启动会先调用loadView,执行完后进入viewDidLoad方法。此时如果在loadView方法中没有给self.view赋值或者没有super loadView,并且在viewDidLoad方法中用到self.view的话,程序就会进入死循环。在Xcode11之前的版本(10.14.6就和11一样了),会一直调用loadView和ViewDidload。在之后的版本还会执行viewWillappear。

(旧版本)
根据打印顺序推测, 应该是Xcode系统的一种防护机制, 当到viewDidLoad时View为空, 此时viewDidLoad中只有

[super viewDidLoad];
NSLog(@"ViewDidLoad"); 
1
2
viewDidLoad完成后, 检测到view为空, 会再调用一次LoadView, 当再次回到ViewDidLoad,发现view还为空时, 系统就会启动防护机制, 阻止再次回到LoadView, 所以结果中, 在两次循环后便停止了循环。

经学长提醒,这种防护机制并非在[super ViewDidLoad]中实现, 我在viewDidLoad中再加一句, 现在代码如下

[super viewDidLoad];
self.view.backgroundColor = [UIColor orangeColor];
NSLog(@"ViewDidLoad"); 
1
2
3
会进入死循环和报错(见下图)他陷入死循环说明走到了self.view这一句(LoadView本来就会因为self.view触发), 那么说明, 这种防护机制在viewDidLoad中实现, 并非在[super viewDidLoad]中实现。

在最新的版本里,会打印很多次viewDidload和loadView;至少比旧版本多。

2.didReceiveMemoryWarning会不会引起死循环。

个人见解:viewDidload正常状态下之后调用一次,执行了didReceiveMemoryWarning后不会再次执行viewDidLoad,所以内存不会再溢出。
viewDidload非正常状态:执行很多次的情况是,loadview执行了很多次,即didReceiveMemoryWarning释放了controller的view,didReceiveMemoryWarning这个方法只会释放视图栈最外层的view,一般controller的view是栈底。这个不好实验让他内存溢出,所以只是个人猜想。

3.layoutSubview触发时机

一:当view的frame或bounds发生改变

1:直接改view的frame或bounds 会调用view中layoutsubview

2:当屏幕旋转的时候,视图控制器中根view发生变化,会调用视图控制中viewDidLayoutsuview)
第二条再议

二:在当前view上addsubvie添加子view,会调用view中layoutSubview
三:改变view的大小的时候或者addSubView,会触发父view的layoutsubview被调用在这里插入图片描述
从上图可以看到将View的layout方法也进行了调用。
四:当UIScroller中滚动的时候,会调用自身layoutsubview.
关于屏幕旋转触发layoutSubview:
当旋转屏幕出现或者消失状态栏的时候,会触发layoutSubview。(所有当前view里的子视图的方法都会触发)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值