应用生命周期
应用的生命周期是以我们点击APP图标之后,从开始到终止(退出)过程中所维护的状态
当我们点击图标之后,应用以main函数为入口,设置AppDelegate
称为函数的代理,接着同时启动主线程的RunLoop
(主线程RunLoop
默认启动将一直存在,它是维持程序生命周期的基本,实质是特殊的do-while
循环,直到程序结束,APP退出,循环结束,关于更多RunLoop的知识可以查看这篇文章),APPDelegate
类在应用生命周期的不同阶段会调用不同的方法,具体过程如图所示:
在此过程中,iOS应用会维持5种状态:
- Not Running(非运行状态):应用没有运行或被系统终止
- Inactive(前台非活动状态):应用正在进入前台的状态,但还不能接受事件的处理
- Active(前台活动状态):应用进入前台状态,可以接受事件处理
- Background(后台状态):应用进入后台后,依然能够执行代码,执行完毕后应用立即进入挂起状态
- Suspended(挂起状态):处于挂起的应用进入一种“冷冻”状态,不能执行代码,如果系统内存不足应用会被终止
代理方法
每种状态的跃迁,都会回调APPDlegate的代理方法,在应用的生命周期中会用到很多方法和通知,以下几种最为常见:
-
application:didFinishLaunchingWithOptions 对应于UIApplicationDidFinishLaunchingNotification的本地通知,程序启动并进行初始化调用该方法并发出通知,这个阶段会实例化根视图控制器
-
applicationDidBecomeActive对应于UIApplicationDidFinishLaunchingNotification的本地通知,应用处于前台非活跃状态时调用该方法并发出通知,这个阶段可以恢复UI的状态
-
applicationWillResignActive对应于UIApplicationWillResignActiveNotification的本地通知,应用将要失去Active状态时调用该方法并发出通知,比如有电话进来或者按下Home键,之后程序进入后台状态
-
applicationDidEnterBackground对应于UIApplicationDidEnterBackgroundNotification的本地通知,应用进入后台时调用该方法并发出通知,这个阶段可以保存用户数据,释放数据库资源
-
applicationWillEnterForeground对应于UIApplicationWillEnterForegroundNotification的本地通知,应用进入前台但还处于活跃状态时调用该方法并发出通知,这个阶段可以恢复用户数据
-
applicationWillTerminate对应于UIApplicationWillTerminateNotification的本地通知,应用被终止时调用该方法并发出通知,这个阶段可以保存用户数据,释放数据库资源
UIViewController 的生命周期
// 非storyBoard(xib或非xib)都走这个方法(注意: 不要在这里做View相关操作,View在loadView方法中才初始化)
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
NSLog(@"%s", __FUNCTION__);
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
}
return self;
}
// 如果连接了串联图storyBoard 走这个方法(init方法和initCoder方法相似,只是被调用的环境不一样,如果用代码进行初始化,会调用init,从nib文件或者归档进行初始化,会调用initCoder)
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
NSLog(@"%s", __FUNCTION__);
if (self = [super initWithCoder:aDecoder]) {
}
return self
}
// xib 加载 完成
- (void)awakeFromNib {
[super awakeFromNib];
NSLog(@"%s", __FUNCTION__);
}
// 加载视图(默认从nib,loadView方法是开始加载视图的起始方法,除非手动调用,否则在ViewController的生命周期中没特殊情况只会被调用一次,需要重写loadView方法的时候,不要调用父类的方法)
- (void)loadView {
NSLog(@"%s", __FUNCTION__);
self.view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.view.backgroundColor = [UIColor redColor];
}
//视图控制器中的视图加载完成,viewController自带的view加载完成
- (void)viewDidLoad {
NSLog(@"%s", __FUNCTION__);
[super viewDidLoad];
}
//视图将要出现(这个方法中完成任何与视图显示相关的任务,例如改变视图方向、状态栏方向、视图显示样式等)
- (void)viewWillAppear:(BOOL)animated {
NSLog(@"%s", __FUNCTION__);
[super viewWillAppear:animated];
}
// view 即将布局其 Subviews(view的bounds改变了,要调整Subviews的位置,在调整之前要做的一些工作就可以在该方法中实现,如状态栏从不显示到显示,视图方向变化)
- (void)viewWillLayoutSubviews {
NSLog(@"%s", __FUNCTION__);
[super viewWillLayoutSubviews];
}
// view 已经布局其 Subviews(view的bounds改变了,已经调整Subviews的位置,在调整完成之后要做的一些工作就可以在该方法中实现)
- (void)viewDidLayoutSubviews {
NSLog(@"%s", __FUNCTION__);
[super viewDidLayoutSubviews];
}
//视图已经出现(这个方法中执行视图显示相关附件任务)
- (void)viewDidAppear:(BOOL)animated {
NSLog(@"%s", __FUNCTION__);
[super viewDidAppear:animated];
}
//视图将要消失(视图将被从屏幕上移除之前执行,view即将从superView中移除且移除动画切换之前,此时还没有调用removeFromSuperview)
- (void)viewWillDisappear:(BOOL)animated {
NSLog(@"%s", __FUNCTION__);
[super viewWillDisappear:animated];
}
//视图已经消失(视图已经被从屏幕上移除,用户看不到这个视图了,view从superView中移除,移除动画切换之后调用,此时已调用removeFromSuperview)
- (void)viewDidDisappear:(BOOL)animated {
NSLog(@"%s", __FUNCTION__);
[super viewDidDisappear:animated];
}
//出现内存警告 (模拟内存警告:点击模拟器->hardware-> Simulate Memory Warning)
- (void)didReceiveMemoryWarning {
NSLog(@"%s", __FUNCTION__);
[super didReceiveMemoryWarning];
}
// 视图被销毁(viewController被释放时调用。视图view被销毁,此处需要对你在init和viewDidLoad中创建的对象进行释放,如定时器与通知的移除)
- (void)dealloc {
NSLog(@"%s", __FUNCTION__);
}
严格意义说一个ViewController
完整的声明周期还应该包括initialize这个方法,这个方法经常与load作为面试题来问,而了解这两个方法的调用时机也很重要,关于这两个方法的介绍,可以点击这里