iOS-App Life Cycle

iOS frameworks是基于MVC设计模式搭建的,本文介绍了其App Life Cycle(生命周期)。

The Main Function

与其他C语言开发的App一样,iOS Apps的入口也是main函数。main函数的唯一作用就是将任务委托为UIKit FrameworksUIKit Frameworks负责创建Core Objects,从storyboard文件中加载界面,调用初始化的App设置代码,并启动Run Loop。

1
2
3
4
5
6
7
8
9
#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int main(int argc, char * argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

The structure of an App

在启动App过程中,UIApplicationMain函数创建了一些Key Objects,并启动App,如下图。每个iOS app的核心是一个UIApplication对象,UIApplication对象负责管理在系统和app的其他对象之间的交互。

The structure of an 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,这一行为保证了用户相关的事件被顺序地处理。下图展示了事件处理流程。

The Main Run Loop

当用户与设备进行交互时,系统创建交互事件,并通过UIKit的一个特殊的端口,将其分发给App,并在App的MainRunLoop中进入处理队列,UIApplication对象首先接收事件,并决定需要进行什么操作。例如,一个Touch事件,通常被分发到当前UIWindow,并进一步分发给对应的View。

Execution States for Apps

App的状态转换由系统控制,例如,用户按下Home键,或者来电时等事件发生时,App的状态将会发生变化,转换图如下:

Execution States for Apps

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 TerminationApp Life Cycle的一环,App应该在即将被中断时进行数据保存。系统经常会中断App以释放内存,另外,在App发生异常行为的时候,系统也会中断App(即常说的Crash)。

Suspended的App被中断时,将不会收到通知,只有处于Background状态的App会收到applicationWillTerminate回调通知,另外,系统重新启动时,也不会收到通知。

除了系统,用户也可以通过双击Home键启动多任务管理的方式,中断App,这种情况下,也不会收到通知。

ViewController Life Cycle

ViewController的生命周期如下:

iOS-ViewController-LifeCycle

两个ViewController之间进行切换时,顺序如下:

iOS-ViewController-LifeCycle-Two

注意:B的viewWillAppear在A的viewWillDisappear后,viewDidAppear在A的viewDidDisappear后。

这其中的某些回调是可能不出现的,例如:

如果在A的viewDidLoad函数中,Push B,且设置animated为YES:

1
2
3
4
5
6
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"A:viewDidLoad");
[self.navigationController pushViewController:[CLWechatDetailViewController new] animated:YES];
}

结果为:

1
2
3
4
5
6
7
A:viewDidLoad
A:viewWillAppear
B:viewDidLoad
A:viewWillDisappear
B:viewWillAppear
A:viewDidDisappear
B:viewDidAppear

A的viewDidAppear没有出现。

如果设置animated为NO, 则结果为:

1
2
3
4
A:viewDidLoad
B:viewDidLoad
B:viewWillAppear
B:viewDidAppear

A只出现了viewDidLoad回调。

结论:

  • 只要执行了Push操作,viewDidAppear就不会被调用;
  • 如果VC的View已经绘制完成,准备显示(Push:Animated:YES),则viewWillAppear被调用,否则(Push:Animated:NO),viewWillAppear不会被调用;
  • viewWillAppear被调用时,viewWillDisappear和viewDidDisappear才会被调用。

流程图如下:

iOS-ViewController-LifeCycle-Push

如果在A的viewWillAppear函数中,Push B,且设置animated为NO:

1
2
3
4
5
6
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(@"A:viewWillAppear");
[self.navigationController pushViewController:[CLWechatDetailViewController new] animated:NO];
}

结果为:

1
2
3
4
5
6
A:viewDidLoad
A:viewWillAppear
A:viewWillDisappear
A:viewDidDisappear
B:viewDidLoad
B:viewWillAppear

结论:A的viewDidDisappear和B的viewWillAppear之间并没有先后关系,两个will之间有,两个did之间也有,参考上图。