背景
隨著App幾年以來不斷的迭代開發(fā),各種sdk集成,日志監(jiān)控,bugly接入等等,啟動(dòng)時(shí)間越來越長(zhǎng),深入了解下ios程序啟動(dòng)運(yùn)行狀態(tài),為后續(xù)的啟動(dòng)優(yōu)化做準(zhǔn)備。
了解應(yīng)用生命周期有什么意義?
iOS系統(tǒng)的資源是有限的,如何能利用有限的資源,發(fā)揮出最大的作用,這就是一個(gè)優(yōu)秀的程序猿應(yīng)該思考的問題。
應(yīng)用程序不同狀態(tài)切換時(shí),需要處理的工作也不相同。不同的狀態(tài),處理不同的代碼,
這樣可以優(yōu)化用戶的體驗(yàn)和電池性能,而且冷啟動(dòng)時(shí)長(zhǎng)是App性能的重要指標(biāo)
了解應(yīng)用程序的狀態(tài)
| 狀態(tài) | 說明 | |
|---|---|---|
| Not running | 未運(yùn)行 | 程序沒啟動(dòng) |
| Inactive | 未激活 | 程序在前臺(tái)運(yùn)行,不過沒有接收到事件。 |
| Active | 激活 | 程序在前臺(tái)運(yùn)行而且接收到了事件。 |
| Backgroud | 后臺(tái) | 程序在后臺(tái)而且能執(zhí)行代碼,大多數(shù)程序進(jìn)入這個(gè)狀態(tài)后會(huì)在在這個(gè)狀態(tài)上停留一會(huì)。時(shí)間到之后會(huì)進(jìn)入掛起狀態(tài)(Suspended)。有的程序經(jīng)過特殊的請(qǐng)求后可以長(zhǎng)期處于Backgroud狀態(tài) |
| Suspended | 掛起 | 程序在后臺(tái)不能執(zhí)行代碼。系統(tǒng)會(huì)自動(dòng)把程序變成這個(gè)狀態(tài)而且不會(huì)發(fā)出通知。當(dāng)掛起時(shí),程序還是停留在內(nèi)存中的,當(dāng)系統(tǒng)內(nèi)存低時(shí),系統(tǒng)就把掛起的程序清除掉,為前臺(tái)程序提供更多的內(nèi)存。 |
狀態(tài)圖:

ios程序入口main函數(shù)
一般所有基于C編寫的app的入口都是main函數(shù),但iOS應(yīng)用程序有點(diǎn)不同。你無需自己創(chuàng)建main函數(shù),在使用Xcode創(chuàng)建工程的時(shí)候就已經(jīng)幫你提供了。除非一些特殊情況,否則你不應(yīng)該修改Xcode提供的main函數(shù)實(shí)現(xiàn)。
在ios的App中,大大弱化了main函數(shù),它的主要工作都交給了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:一個(gè)很重要的函數(shù),它主要是創(chuàng)建app的幾個(gè)核心對(duì)象來處理以下過程:
- 從可用
Storyboard文件加載用戶界面 - 調(diào)用
AppDelegate自定義代碼來做一些初始化設(shè)置 - 將app放入Main Run Loop環(huán)境中來響應(yīng)和處理與用戶交互產(chǎn)生的事件
注:一個(gè)應(yīng)用程序可以有一個(gè)主的storyboard文件或者有一個(gè)主的nib文件,但不能同時(shí)有兩個(gè)存在。
每個(gè)iPhone應(yīng)用程序都有一個(gè)
UIApplication,它主要有2個(gè)任務(wù)。
1、負(fù)責(zé)初始化并顯示UIWindow,負(fù)責(zé)加載應(yīng)用程序的第一個(gè)UIView到UIWindow窗體中。
2、幫助管理應(yīng)用程序的生命周期,UIApplicationDelegate的代理類來履行這個(gè)任務(wù)。
雖然UIApplication 會(huì)負(fù)責(zé)接收事件,但是UIApplicationDelegate則決定應(yīng)用程序如何去響應(yīng)這些事 件,包括應(yīng)用程序的生命周期事件(比如程序啟動(dòng)和關(guān)閉)、系統(tǒng)事件(比如來電、記事項(xiàng)警 告)
此處只闡述代理方法:
應(yīng)用程序完成啟動(dòng)以后調(diào)用的方法didFinishLaunchingWithOptions:
didFinishLaunchingWithOptions的幾種啟動(dòng)類型介紹
/// 這個(gè)方法是你在啟動(dòng)時(shí)的第一次機(jī)會(huì)來執(zhí)行代碼
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(@"%@", NSStringFromSelector(_cmd));
return YES;
}
應(yīng)用程序即將從活躍狀態(tài)切換到不活躍狀態(tài)時(shí)調(diào)用applicationWillResignActive:
/**
這種情況會(huì)在某些臨時(shí)中斷的事情下發(fā)生(比如來電話,來短信等)或者用戶退出應(yīng)用程序時(shí)發(fā)生。
并且應(yīng)用程序開始轉(zhuǎn)換到后臺(tái)狀態(tài)。
后臺(tái)切換到前臺(tái): 后臺(tái) ---> 不活躍狀態(tài) --> 前臺(tái)(活躍狀態(tài))
前臺(tái)切換到后臺(tái): 前臺(tái)(活躍狀態(tài)) --> 不活躍狀態(tài) --> 后臺(tái)
*/
- (void)applicationWillResignActive:(UIApplication *)application{
NSLog(@"%@", NSStringFromSelector(_cmd));
//使用這個(gè)方法,我們可以暫停正在執(zhí)行的任務(wù),停用定時(shí)器,降低OpenGL ES的描繪幀率,游戲應(yīng)該在這個(gè)方法中暫停。
}
應(yīng)用程序進(jìn)入到后臺(tái)后調(diào)用的方法applicationDidEnterBackground:
- (void)applicationDidEnterBackground:(UIApplication *)application {
// 在這個(gè)方法中,我們可以釋放共享的資源,保存用戶數(shù)據(jù),使定時(shí)器無效,并且保存足夠多的應(yīng)用程序狀態(tài)信息用來恢復(fù)應(yīng)用程序當(dāng)前的狀態(tài)。
// 配置應(yīng)用程序是否能夠在后臺(tái): 在Info.plist添加一項(xiàng):Application does not run in background YES 不支持后臺(tái)運(yùn)行 NO 支持后臺(tái)運(yùn)行
// 當(dāng)用戶退出應(yīng)用程序時(shí),如果你的應(yīng)用程序支持后臺(tái)運(yùn)行,這個(gè)方法會(huì)被調(diào)用.如果你的應(yīng)用程序不支持后臺(tái)運(yùn)行,applicationWillTerminate:這個(gè)方法會(huì)被調(diào)用。
NSLog(@"%@", NSStringFromSelector(_cmd));
}
應(yīng)用程序即將進(jìn)入到前臺(tái)時(shí)調(diào)用的方法applicationWillEnterForeground:
- (void)applicationWillEnterForeground:(UIApplication *)application {
// 這個(gè)方法作為從后臺(tái)進(jìn)入不活躍狀態(tài)的時(shí)候調(diào)用的方法。在這兒,你可以撤銷在進(jìn)入后臺(tái)后做的許多改變。(恢復(fù)用戶數(shù)據(jù))
NSLog(@"%@", NSStringFromSelector(_cmd));
}
應(yīng)用程序已經(jīng)成為活躍狀態(tài)后調(diào)用的方法applicationDidBecomeActive:
- (void)applicationDidBecomeActive:(UIApplication *)application {
// 在這個(gè)方法中,重啟之前被暫停的任務(wù)(或者還沒有啟動(dòng)的任務(wù)),如果應(yīng)用程序之前在后臺(tái)運(yùn)行,我們可以選擇刷新用戶界面。
NSLog(@"%@", NSStringFromSelector(_cmd));
}
應(yīng)用程序即將終止時(shí)調(diào)用applicationWillTerminate:
- (void)applicationWillTerminate:(UIApplication *)application {
// 在這個(gè)方法中保存合適的數(shù)據(jù)。
NSLog(@"%@", NSStringFromSelector(_cmd));
}
應(yīng)用程序收到內(nèi)存警告時(shí)調(diào)用的方法applicationDidReceiveMemoryWarning:
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
// 釋放暫時(shí)無用的資源
NSLog(@"%@", NSStringFromSelector(_cmd));
}
示例:
1、運(yùn)行程序會(huì)調(diào)用如下代理方法:

2、按Home

3、再次點(diǎn)擊程序

4、只有當(dāng)應(yīng)用被系統(tǒng)殺死的時(shí)候才會(huì)調(diào)用這個(gè)方法:applicationWillTerminate
什么時(shí)候會(huì)調(diào)用applicationWillTerminate
5、當(dāng)收到推送通知的時(shí)候會(huì)調(diào)用這個(gè)方法:applicationWillResignActive
6、在彈出的通知橫幅處向上滑動(dòng),讓橫幅消失: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
http://m.itdecent.cn/p/fc675b077756
https://blog.csdn.net/totogo2010/article/details/8048652
http://m.itdecent.cn/p/aa50e5350852