iOS frameworks是基于MVC设计模式搭建的,本文介绍了其App Life Cycle(生命周期)。
The Main Function
与其他C语言开发的App一样,iOS Apps的入口也是main函数。main函数的唯一作用就是将任务委托为UIKit Frameworks。UIKit Frameworks负责创建Core Objects,从storyboard文件中加载界面,调用初始化的App设置代码,并启动Run Loop。
1 | #import <UIKit/UIKit.h> |
The structure of an App
在启动App过程中,UIApplicationMain函数创建了一些Key Objects,并启动App,如下图。每个iOS app的核心是一个UIApplication对象,UIApplication对象负责管理在系统和app的其他对象之间的交互。
Name | Function |
---|---|
UIApplication | 负责管理Event Loop,以及其他一些较底层的app行为,同时,它负责传递app的状态变化和一些特殊的事件(例如,推送)给UIApplicationDelegate |
UIWindow | 负责呈现views到屏幕上,另外,为了管理views,UIWindow与UIApplication一起协作分发事件到Views和ViewControllers |
The Main Run Loop
App的Main Run Loop负责处理所有与用户相关的事件,UIApplication在主线程创建了Main Run Loop,这一行为保证了用户相关的事件被顺序地处理。下图展示了事件处理流程。
当用户与设备进行交互时,系统创建交互事件,并通过UIKit的一个特殊的端口,将其分发给App,并在App的MainRunLoop中进入处理队列,UIApplication对象首先接收事件,并决定需要进行什么操作。例如,一个Touch事件,通常被分发到当前UIWindow,并进一步分发给对应的View。
Execution States for Apps
App的状态转换由系统控制,例如,用户按下Home键,或者来电时等事件发生时,App的状态将会发生变化,转换图如下:
State | Function |
---|---|
Not Running | App未启动,或者被系统中断 |
Inactive | App在前台运行,但是没准备好接收事件,App只有在切换状态时,会短暂处于Inactive状态下(切到后台前,也会先进入Inactive状态) |
Active | App在前台运行,并可以接收事件 |
Background | App在后台运行并执行代码,大多数App在切换到Suspend状态前,会短暂进入Background状态下,有时,一些App会在这一状态下运行一段时间处理一些事件,另外,一个App在启动时如果直接被切到后台,将会直接进入Background状态,而不会进入Inactive状态 |
Suspended | App在后台运行,没有执行代码,系统会自动将App切到Suspended状态,而不会进行通知,如果遇到内存不足时,系统可能会直接将Suspended状态的App直接从内存中清除 |
大多数状态的变化都有回调:
Delegate | Function |
---|---|
application:willFinishLaunchingWithOptions: | App启动时 |
application:didFinishLaunchingWithOptions: | 在App启动,即将呈现给用户时 |
applicationDidBecomeActive: | 变成Active状态时,例如切到前台 |
applicationWillResignActive: | 即将从Active状态切换到其他状态时,例如来电 |
applicationDidEnterBackground: | 变成Background状态时,例如切到后台 |
applicationWillEnterForeground: | App切回前台,但还没变成Active状态 |
applicationWillTerminate: | App被中断时,注意切换到Suspended状态不会回调 |
App Termination
App Termination是App Life Cycle的一环,App应该在即将被中断时进行数据保存。系统经常会中断App以释放内存,另外,在App发生异常行为的时候,系统也会中断App(即常说的Crash)。
Suspended的App被中断时,将不会收到通知,只有处于Background状态的App会收到applicationWillTerminate回调通知,另外,系统重新启动时,也不会收到通知。
除了系统,用户也可以通过双击Home键启动多任务管理的方式,中断App,这种情况下,也不会收到通知。
ViewController Life Cycle
ViewController的生命周期如下:
两个ViewController之间进行切换时,顺序如下:
注意:B的viewWillAppear在A的viewWillDisappear后,viewDidAppear在A的viewDidDisappear后。
这其中的某些回调是可能不出现的,例如:
如果在A的viewDidLoad函数中,Push B,且设置animated为YES:
1 | - (void)viewDidLoad |
结果为:
1 | A:viewDidLoad |
A的viewDidAppear没有出现。
如果设置animated为NO, 则结果为:
1 | A:viewDidLoad |
A只出现了viewDidLoad回调。
结论:
- 只要执行了Push操作,viewDidAppear就不会被调用;
- 如果VC的View已经绘制完成,准备显示(Push:Animated:YES),则viewWillAppear被调用,否则(Push:Animated:NO),viewWillAppear不会被调用;
- viewWillAppear被调用时,viewWillDisappear和viewDidDisappear才会被调用。
流程图如下:
如果在A的viewWillAppear函数中,Push B,且设置animated为NO:
1 | - (void)viewWillAppear:(BOOL)animated |
结果为:
1 | A:viewDidLoad |
结论:A的viewDidDisappear和B的viewWillAppear之间并没有先后关系,两个will之间有,两个did之间也有,参考上图。