背景
随着App几年以来不断的迭代开发,各种sdk集成,日志监控,bugly接入等等,启动时间越来越长,深入了解下ios程序启动运行状态,为后续的启动优化做准备。
了解应用生命周期有什么意义?
iOS系统的资源是有限的,如何能利用有限的资源,发挥出最大的作用,这就是一个优秀的程序猿应该思考的问题。
应用程序不同状态切换时,需要处理的工作也不相同。不同的状态,处理不同的代码,
这样可以优化用户的体验和电池性能,而且冷启动时长是App性能的重要指标
了解应用程序的状态
状态 | 说明 | |
---|---|---|
Not running | 未运行 | 程序没启动 |
Inactive | 未激活 | 程序在前台运行,不过没有接收到事件。 |
Active | 激活 | 程序在前台运行而且接收到了事件。 |
Backgroud | 后台 | 程序在后台而且能执行代码,大多数程序进入这个状态后会在在这个状态上停留一会。时间到之后会进入挂起状态(Suspended)。有的程序经过特殊的请求后可以长期处于Backgroud状态 |
Suspended | 挂起 | 程序在后台不能执行代码。系统会自动把程序变成这个状态而且不会发出通知。当挂起时,程序还是停留在内存中的,当系统内存低时,系统就把挂起的程序清除掉,为前台程序提供更多的内存。 |
状态图:
ios程序入口main函数
一般所有基于C编写的app的入口都是main
函数,但iOS应用程序有点不同。你无需自己创建main函数,在使用Xcode创建工程的时候就已经帮你提供了。除非一些特殊情况,否则你不应该修改Xcode提供的main
函数实现。
在ios的App中,大大弱化了main函数,它的主要工作都交给了UIKit framework
示例代码如下:
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
UIApplicationMain:一个很重要的函数,它主要是创建app的几个核心对象来处理以下过程:
- 从可用
Storyboard
文件加载用户界面 - 调用
AppDelegate
自定义代码来做一些初始化设置 - 将app放入Main Run Loop环境中来响应和处理与用户交互产生的事件
注:一个应用程序可以有一个主的storyboard文件或者有一个主的nib文件,但不能同时有两个存在。
每个iPhone应用程序都有一个
UIApplication
,它主要有2个任务。
1、负责初始化并显示UIWindow
,负责加载应用程序的第一个UIView到UIWindow窗体中。
2、帮助管理应用程序的生命周期,UIApplicationDelegate
的代理类来履行这个任务。
虽然UIApplication 会负责接收事件,但是UIApplicationDelegate则决定应用程序如何去响应这些事 件,包括应用程序的生命周期事件(比如程序启动和关闭)、系统事件(比如来电、记事项警 告)
此处只阐述代理方法:
应用程序完成启动以后调用的方法didFinishLaunchingWithOptions
:
didFinishLaunchingWithOptions的几种启动类型介绍
/// 这个方法是你在启动时的第一次机会来执行代码
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(@"%@", NSStringFromSelector(_cmd));
return YES;
}
应用程序即将从活跃状态切换到不活跃状态时调用applicationWillResignActive
:
/**
这种情况会在某些临时中断的事情下发生(比如来电话,来短信等)或者用户退出应用程序时发生。
并且应用程序开始转换到后台状态。
后台切换到前台: 后台 ---> 不活跃状态 --> 前台(活跃状态)
前台切换到后台: 前台(活跃状态) --> 不活跃状态 --> 后台
*/
- (void)applicationWillResignActive:(UIApplication *)application{
NSLog(@"%@", NSStringFromSelector(_cmd));
//使用这个方法,我们可以暂停正在执行的任务,停用定时器,降低OpenGL ES的描绘帧率,游戏应该在这个方法中暂停。
}
应用程序进入到后台后调用的方法applicationDidEnterBackground
:
- (void)applicationDidEnterBackground:(UIApplication *)application {
// 在这个方法中,我们可以释放共享的资源,保存用户数据,使定时器无效,并且保存足够多的应用程序状态信息用来恢复应用程序当前的状态。
// 配置应用程序是否能够在后台: 在Info.plist添加一项:Application does not run in background YES 不支持后台运行 NO 支持后台运行
// 当用户退出应用程序时,如果你的应用程序支持后台运行,这个方法会被调用.如果你的应用程序不支持后台运行,applicationWillTerminate:这个方法会被调用。
NSLog(@"%@", NSStringFromSelector(_cmd));
}
应用程序即将进入到前台时调用的方法applicationWillEnterForeground
:
- (void)applicationWillEnterForeground:(UIApplication *)application {
// 这个方法作为从后台进入不活跃状态的时候调用的方法。在这儿,你可以撤销在进入后台后做的许多改变。(恢复用户数据)
NSLog(@"%@", NSStringFromSelector(_cmd));
}
应用程序已经成为活跃状态后调用的方法applicationDidBecomeActive
:
- (void)applicationDidBecomeActive:(UIApplication *)application {
// 在这个方法中,重启之前被暂停的任务(或者还没有启动的任务),如果应用程序之前在后台运行,我们可以选择刷新用户界面。
NSLog(@"%@", NSStringFromSelector(_cmd));
}
应用程序即将终止时调用applicationWillTerminate
:
- (void)applicationWillTerminate:(UIApplication *)application {
// 在这个方法中保存合适的数据。
NSLog(@"%@", NSStringFromSelector(_cmd));
}
应用程序收到内存警告时调用的方法applicationDidReceiveMemoryWarning
:
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
// 释放暂时无用的资源
NSLog(@"%@", NSStringFromSelector(_cmd));
}
示例:
1、运行程序会调用如下代理方法:
2、按Home
3、再次点击程序
4、只有当应用被系统杀死的时候才会调用这个方法:applicationWillTerminate
什么时候会调用applicationWillTerminate
5、当收到推送通知的时候会调用这个方法:applicationWillResignActive
6、在弹出的通知横幅处向上滑动,让横幅消失:applicationDidBecomeActive
参考文章:
App Programming Guide for iOS
https://www.cnblogs.com/jukaiit/p/5615492.html
http://ios.dovov.com/applicationwillterminate-3.html
https://blog.csdn.net/totogo2010/article/details/8048652
https://www.jianshu.com/p/fc675b077756
https://blog.csdn.net/totogo2010/article/details/8048652
https://www.jianshu.com/p/aa50e5350852