ViewController的生命周期

一、结构

按结构可以对iOS的所有ViewController分成两类:
1、主要用于展示内容的ViewController,这种ViewController主要用于为用户展示内容,并与用户交互,如UITableViewController,UIViewController。
2、用于控制和显示其他ViewController的ViewController。这种ViewController一般都是一个ViewController的容器。如UINavigationController,UITabbarController。它们都有一个属性:viewControllers。其中UINavigationController表示一种Stack式结构,push一个ViewController或pop一次,因此后一个ViewController一般会依赖前一个ViewController。而UITabbarController表示一个Array结构,各个ViewController是并列的。
第一种ViewController会经常被继承,用来显示不同的数据给用户。而第二种很少被继承,除非你真的需要自定义它。
注:细心的同学应该能发现,在Xcode中新建一个ViewController时,只可以选择继承自UIViewController和UITableViewController,而它们都是第一种。

#Stack式结构:一种栈结构,当应用开始以后,函数main() 被调用,一些空间分配在”stack” 中。这是为应用分配的另一个段的内存空间,这是为了函数变量存储需要而分配的内存。每一次在应用中调用一个函数,“stack ”的一部分会被分配在”stack” 中,称之为”frame” 。新函数的本地变量分配在这里。正如名称所示,“stack ”是后进先出(LIFO )结构。当函数调用其他的函数时,“stack frame ”会被创建;当其他函数退出后,这个“frame ”会自动被破坏。

二、Controller和View的生命周期

这里指的View是指Controller的View。它作为Controler的属性,生命周期在Controller的生命周期内。就是说你的Controller不能在view释放前就释放了。当你alloc并init了一个ViewController时,这个ViewController应该是还没有创建view的。ViewController的view是使用了lazyInit方式创建,就是说你调用的view属性的getter:[self view]。在getter里会先判断view是否创建,如果没有创建,那么会调用loadView来创建view。loadView完成时会继续调用viewDidLoad。loadView和viewDidLoad的一个区别就是:loadView时还没有view。而viewDidLoad时view以及创建好了。
当view被添加其他view中之前时,会调用viewWillAppear,而之后会调用viewDidAppear。
当view从其他view中移出之前时,会调用viewWillDisAppear,而之后会调用viewDidDisappear。
当view不在使用,而且是disappeared,受到内存警告时,那么viewController会将view释放并将其指向nil。

这里可以有个关于ios如何init的结论:

(loadView/nib文件)来加载view到内存 ——>

viewDidLoad函数进一步初始化这些view ——>

内存不足时,调用viewDidUnload函数释放views—->

当需要使用view时有回到第一步

三。测试

首先关于xib是什么可以查看:https://www.jianshu.com/p/31dd2d6b16aa

接下来就可以了解https://www.jianshu.com/p/d60b388b19f5(直接看第二部分就行了)

看完之后最重要的结论:

  • 只有init系列的方法,如initWithNibName需要自己调用,其他方法如loadViewawakeFromNib则是系统自动调用。而viewWill/Did系列的方法则类似于回调和通知,也会被自动调用。

  • 纯代码写视图布局时需要注意,要手动调用loadView方法,而且不要调用父类的loadView方法。纯代码和用IB的区别仅存在于loadView方法及其之前,编程时需要注意的也就是loadView方法。

  • 除了initWithNibNameawakeFromNib方法是处理视图控制器外,其他方法都是处理视图。这两个方法在视图控制器的生命周期里只会调用一次。

可以给大家看看:

当一个视图控制器被创建,并在屏幕上显示的时候。 代码的执行顺序
1、 alloc                                   创建对象,分配空间
2、init (initWithNibName) 初始化对象,初始化数据
3、loadView                          从nib载入视图 ,通常这一步不需要去干涉。除非你没有使用xib文件创建视图
4、viewDidLoad                   载入完成,可以进行自定义数据以及动态创建其他控件
5、viewWillAppear              视图将出现在屏幕之前,马上这个视图就会被展现在屏幕上了
6、viewDidAppear               视图已在屏幕上渲染完成

当一个视图被移除屏幕并且销毁的时候的执行顺序,这个顺序差不多和上面的相反
1、viewWillDisappear            视图将被从屏幕上移除之前执行
2、viewDidDisappear             视图已经被从屏幕上移除,用户看不到这个视图了
3、dealloc                                 视图被销毁,此处需要对你在init和viewDidLoad中创建的对象进行释放

四。例子

给TableViewCell加上生命周期事件(如cellWillAppear)

        要实现cellWillAppear,大约得在tableView:willDisplayCell:forIndexPath:中,对各cell进行cellWillAppear的调用

  • 由于tableView:willDisplayCell:forIndexPath:是个protocol,并没有默认实现,则需要找到一个其实现的基础
  • 由于TableView的delegate可以实现在单独的类中,因此考虑创建一个用于此目的的基类:MDTableViewDelegate,这个类中实现此protocol中的tableView:willDisplayCell:forIndexPath:。如此,TableView将其delegate设置到MDTableViewDelegate的子类即可使其cell获得cellWillAppear的调用。
  • 等一下!由于用户可能会override tableView:willDisplayCell:forIndexPath:用于自己的实现,因此上面一步还需要一些额外处理。没错,可以用method swizzling创建一个类。
  • method swizzling实现在哪?
    • 如果直接实现在MDTableViewDelegate中,那么若子类的实现了tableView:willDisplayCell:forIndexPath:,则必须显示的调用[super tableView:willDisplayCell:forIndexPath]。

#protocol意思是是协议,override意思是覆写,method swizzing用于改变一个已经存在的 selector 的实现,可以参考:https://nshipster.cn/method-swizzling/

猜你喜欢

转载自blog.csdn.net/Miaoleigemi/article/details/81167988