iOS 應(yīng)用程序生命周期

iOS 應(yīng)用程序一般都是由自己編寫的代碼和系統(tǒng)框架(system frameworks)組成托启,系統(tǒng)框架提供一些基本infrastructure給所有 app 來運行葫慎,而你提供自己編寫的代碼來定制app的外觀和行為。因此腥寇,了解iOS infrastructure 和它們?nèi)绾喂ぷ鲗帉慳pp是很有幫助的挡毅。

iOS 應(yīng)用程序的啟動執(zhí)行順序

啟動順序

首先,來了解一下這張圖


iOS 程序啟動圖

以上零蓉,就是一個應(yīng)用程序的執(zhí)行順序。接下來穷缤,讓我們具體的了解一下這個流程

  1. 程序入口:
    執(zhí)行 main 函數(shù),設(shè)置 AppDelegate 稱為函數(shù)的代理
  2. 程序完成加載
    [AppDelegate application:didFinishLaunchingWithOptions:]
  3. 創(chuàng)建 window 窗口
  4. 程序被激活
    [AppDelegate applicationDidBecomeActive:]
  5. 當(dāng)點擊 home 鍵時:
    程序取消激活狀態(tài)
    [AppDelegate applicationWillResignActive:]
    程序進(jìn)入后臺
    [AppDelegate applicationDidEnterBackground:]
  6. 點擊進(jìn)入項目工程中:
    程序進(jìn)入前臺
    [AppDelegate applicationWillEnterForeground:]
    程序重新激活
    [AppDelegate applicationDidBecomeActive:]

iOS 程序的狀態(tài)

從上面的這個流程箩兽,我們可以發(fā)現(xiàn)它包括幾個狀態(tài):后臺津肛、前臺、激活汗贫、未激活身坐。其實,iOS的應(yīng)用程序共有5種狀態(tài):

  • Not running(未運行):程序未啟動
  • Inactive(未激活):其他兩個狀態(tài)切換時出現(xiàn)的短暫狀態(tài)落包。當(dāng)用戶鎖屏或者系統(tǒng)提示用戶去響應(yīng) Alert窗口(如來電部蛇、信息等)時
  • Active(激活):在屏幕下顯示正常的運行狀態(tài),該狀態(tài)下可以接受用戶輸入并及時更新顯示
  • Background(后臺)::程序在后臺且能執(zhí)行代碼咐蝇。用戶按下Home鍵不久后進(jìn)入此狀態(tài)(先進(jìn)入了Inactive狀態(tài)涯鲁,再進(jìn)入Background狀態(tài)),然后會迅速進(jìn)入掛起狀態(tài)(Suspended)有序。有的程序經(jīng)過特殊的請求后可以長期處于Backgroud狀態(tài)
  • Suspended (掛起):程序在后臺不能執(zhí)行代碼抹腿。普通程序在進(jìn)入Background狀態(tài)不久后就會進(jìn)入此狀態(tài)。當(dāng)掛起時旭寿,程序還是停留在內(nèi)存中的警绩,當(dāng)系統(tǒng)內(nèi)存低時,系統(tǒng)就把掛起的程序清除掉盅称,為前臺程序提供更多的內(nèi)存

轉(zhuǎn)換過程如圖:


狀態(tài)轉(zhuǎn)換

程序的入口

首先肩祥,下面的函數(shù)就是我們經(jīng)常看到的 main 函數(shù)

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

main函數(shù)的兩個參數(shù)缩膝,iOS中沒有用到混狠,包括這兩個參數(shù)是為了與標(biāo)準(zhǔn)ANSI C保持一致。我們接著看 UIApplicationMain 的參數(shù)逞盆,前兩個和 main 函數(shù)的相同檀蹋,重點是后面的兩個,在官方文檔中是這樣說明的。

/ If nil is specified for principalClassName, the value for NSPrincipalClass from the Info.plist is used. If there is no  
// NSPrincipalClass key specified, the UIApplication class is used. The delegate class will be instantiated using init.  
UIKIT_EXTERN int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);  

后兩個參數(shù)分別表示程序的主要類(principal class)和代理類(delegate class)俯逾。如果主要類(principal class)為nil贸桶,將從Info.plist中獲取,如果Info.plist中不存在對應(yīng)的key桌肴,則默認(rèn)為UIApplication皇筛;如果代理類(delegate class)將在新建工程時創(chuàng)建。

AppDelegate類

不知道大家有沒有認(rèn)真去研究過我們工程里的 AppDelegate 這個類里的內(nèi)容呢坠七?其實水醋,它關(guān)乎著整個應(yīng)用程序的生命周期,它包含的6個類方法就是在這幾個狀態(tài)切換過程中調(diào)用的彪置。
以下代碼就是 AppDelegate.m 中的方法

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 程序完成載入
    NSLog(@"--- %s ---",__func__); //__func__打印方法名
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    PCCTabBarController *tabBarVC = [[PCCTabBarController alloc] init];
    self.window.rootViewController = tabBarVC;
    [self.window makeKeyAndVisible];
    
    return YES;
}


- (void)applicationWillResignActive:(UIApplication *)application {
    NSLog(@"--- %s ---",__func__);
    /* 當(dāng)應(yīng)用程序從活動狀態(tài)(active)變到非活動狀態(tài)(inactive時被觸發(fā)調(diào)用拄踪, 這可能發(fā)生在一些臨時中斷下(例如:來電話、來短信)又或者程序退出時拳魁,他會先過渡到后臺然后terminate 使用這方法去暫停正在進(jìn)行的任務(wù)惶桐,禁用計時器,節(jié)流OpenGL ES 幀率潘懊。在游戲中應(yīng)該在這個方法里面暫停游戲姚糊。 */
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}


- (void)applicationDidEnterBackground:(UIApplication *)application {
    NSLog(@"--- %s ---",__func__); //__func__打印方法名
    /* 使用這種方法來釋放共享資源,保存用戶數(shù)據(jù),無效計時器,存儲足夠多的應(yīng)用程序狀態(tài)信息來恢復(fù)您的應(yīng)用程序的當(dāng)前狀態(tài),以防它終止丟失數(shù)據(jù)。 如果你的程序支持后臺運行授舟,那么當(dāng)用戶退出時不會調(diào)用applicationWillTerminate救恨。 */
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}


- (void)applicationWillEnterForeground:(UIApplication *)application {
    /* 先從后臺切換到非活動狀態(tài),然后進(jìn)入活動狀態(tài)释树。 */
    NSLog(@"--- %s ---",__func__);
    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}


- (void)applicationDidBecomeActive:(UIApplication *)application {
    /* 重啟所有的任務(wù)肠槽,不管是從非活動狀態(tài)還是剛啟動程序,還是后臺狀態(tài)躏哩。 */
    NSLog(@"--- %s ---",__func__);
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}


- (void)applicationWillTerminate:(UIApplication *)application {
    /* 終止*/
    NSLog(@"--- %s ---",__func__);
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

接下來署浩,就讓我們新建一個工程,通過實踐看一下它的狀態(tài)轉(zhuǎn)換過程是否和我們上面所說的一樣呢扫尺?

當(dāng)我們啟動程序的時候筋栋,打印的結(jié)果如下:

2017-11-01 16:47:32.092347+0800 PCConnect[917:142442] --- -[AppDelegate application:didFinishLaunchingWithOptions:] ---
2017-11-01 16:47:32.432588+0800 PCConnect[917:142442] --- -[AppDelegate applicationDidBecomeActive:] ---

按下home 鍵時

2017-11-01 16:49:15.906334+0800 PCConnect[917:142442] --- -[AppDelegate applicationWillResignActive:] ---
2017-11-01 16:49:16.736169+0800 PCConnect[917:142442] --- -[AppDelegate applicationDidEnterBackground:] ---

重新打開 APP 時:

2017-11-01 17:51:57.815175+0800 PCConnect[2056:660773] --- -[AppDelegate applicationWillEnterForeground:] ---
2017-11-01 17:51:58.102222+0800 PCConnect[2056:660773] --- -[AppDelegate applicationDidBecomeActive:] ---

我們發(fā)現(xiàn),它和我們上面說的一致正驻。這就是 iOS 程序的狀態(tài)轉(zhuǎn)化的過程弊攘。最后,當(dāng)我們的程序完全要退出時姑曙,將調(diào)用 applicationWillTerminate襟交,來保存用戶的一些重要數(shù)據(jù)以便下次啟動時恢復(fù)到 APP 原來的狀態(tài) 。

iOS 視圖的生命周期

iOS 應(yīng)用的視圖狀態(tài)分為以下幾種:


視圖狀態(tài)

當(dāng)一個視圖控制器被創(chuàng)建到在屏幕上顯示的時候伤靠,代碼的執(zhí)行順序是:

  1. alloc 創(chuàng)建對象捣域、分配空間
  2. init(initWithNibName) 初始化對象,初始化數(shù)據(jù)
  3. loadView 從 nib 載入視圖,通常這步不需要去干涉焕梅。除非你使用純代碼布局迹鹅。
  4. viewDidLoad 載入完成,可以進(jìn)行自定義數(shù)據(jù)以及動態(tài)創(chuàng)建其他控件贞言;
  5. viewWillAppear 視圖將出現(xiàn)在屏幕之前
  6. viewDidAppear 視圖已在屏幕上渲染完成
    而當(dāng)一個視圖被移除屏幕并被銷毀的時候執(zhí)行的順序和上面的差不多相反斜棚,具體的如下:
  7. viewWillDisappear 視圖將被從屏幕上移除之前執(zhí)行
  8. viewDidDisappear 視圖已經(jīng)被從屏幕上移除
  9. dealloc 視圖被銷毀,此處需要對你在 init 和 viewDidLoad 中創(chuàng)建的對象進(jìn)行釋放

UIViewController 視圖調(diào)用的方法

上述對于視圖控制器從創(chuàng)建到銷毀的過程通常包含如下幾種方法该窗,這些方法都是 UIViewController 類的方法:

  • (void)viewDidLoad弟蚀;
  • (void)viewDidUnload;
  • (void)viewWillAppear:(BOOL)animated酗失;
  • (void)viewDidAppear:(BOOL)animated义钉;
  • (void)viewWillDisappear:(BOOL)animated;
  • (void)viewDidDisappear:(BOOL)animated级零;
    那么断医,具體每個函數(shù)的含義以及如何使用,接下來會給大家具體說明:
  1. -(void)viewDidLoad;
    一個 APP 在載入時會先調(diào)用 loadView 方法或者載入 XIB 中創(chuàng)建的初始界面的方法奏纪,將視圖載入到內(nèi)存中;然后會調(diào)用 viewDidLoad 方法來進(jìn)一步的設(shè)置斩启。
    我們會對于各種初始數(shù)據(jù)的載入序调,初始設(shè)定等很多內(nèi)容都會在這個方法中實現(xiàn)。這也是兔簇,我們最常用的一個方法发绢。
  2. -(void)viewDidUnload;
    內(nèi)存足夠的情況下,軟件的視圖通常會一直保存在內(nèi)存中垄琐;一旦內(nèi)存不夠边酒,一些沒有顯示的視圖控制器就會收到內(nèi)存不夠的警告,然后就會釋放自己擁有的視圖狸窘,以達(dá)到釋放內(nèi)存的目的墩朦。但是系統(tǒng)只是釋放內(nèi)存,不會釋放對象的所有權(quán)翻擒,所以通常我們需要在這里將不需要在內(nèi)存中保留的對象釋放所有權(quán)氓涣,也就是將指針置為 nil.
    這個方法通常并不會在視圖變換的時候被調(diào)用,而只會在系統(tǒng)退出或者收到內(nèi)存警告的時候才會被調(diào)用陋气。但是由于我們需要保證在收到內(nèi)存警告的時候能夠?qū)ζ渥鞒龇磻?yīng)劳吠,所以這個方法通常都需要我們?nèi)崿F(xiàn)。
    另外巩趁,即使在設(shè)備上按了Home鍵之后痒玩,系統(tǒng)也不一定會調(diào)用這個方法,因為iOS4之后,系統(tǒng)允許將APP在后臺掛起蠢古,并將其繼續(xù)滯留在內(nèi)存中奴曙,因此,viewcontroller并不會調(diào)用這個方法來清除內(nèi)存便瑟。
  3. -(void)viewWillAppear:(BOOL)animated;
    系統(tǒng)在載入所有數(shù)據(jù)后缆毁,將會在屏幕上顯示視圖,這時會先調(diào)用這個方法到涂。通常我們會利用這個方法脊框,對即將顯示的視圖做進(jìn)一步的設(shè)置。例如践啄,我們可以利用這個方法來設(shè)置設(shè)備不同方向時該如何顯示浇雹。
    另外,當(dāng)APP有多個視圖時屿讽,在視圖間切換時昭灵,并不會再次載入viewDidLoad方法,所以如果在調(diào)入視圖時伐谈,需要對數(shù)據(jù)做更新烂完,就只能在這個方法內(nèi)實現(xiàn)了。
  4. -(void)viewDidAppear:(BOOL)animated诵棵;
    有時候由于一些特殊的原因抠蚣,我們不能在viewWillApper方法里對視圖進(jìn)行更新。那么可以重寫這個方法履澳,在這里對正在顯示的視圖進(jìn)行進(jìn)一步的設(shè)置嘶窄。
  5. -(void)viewWillDisappear:(BOOL)animated;
    在視圖變換時距贷,當(dāng)前視圖在即將被移除柄冲、或者被覆蓋時,會調(diào)用這個方法進(jìn)行一些善后的處理和設(shè)置忠蝗。
    由于在iOS4之后现横,系統(tǒng)允許將APP在后臺掛起,所以在按了Home鍵之后什湘,系統(tǒng)并不會調(diào)用這個方法长赞,因為就這個APP本身而言,APP顯示的view闽撤,仍是掛起時候的view得哆,所以并不會調(diào)用這個方法。
  6. -(void)viewDidDisappear:(BOOL)animated哟旗;
    通過重寫該方法贩据,我們可以對已經(jīng)消失或被覆蓋或已經(jīng)隱藏的視圖做一些其他操作栋操。

iOS 中 loadView 和 viewDidLoad 的區(qū)別

iOS 開發(fā)中必不可少的要用到這兩個方法,他們都可以用來在視圖載入的時候饱亮,初始化一些內(nèi)容矾芙。但是它們的區(qū)別是什么?

  • viewDidLoad 無論你是通過xib文件還是重寫loadView方法創(chuàng)建UIViewController的view近上,在view創(chuàng)建完畢后剔宪,最終都會調(diào)用viewDidLoad方法
  • loadView 每次訪問UIViewController的view(比如controller.view、self.view)而且view為nil壹无,loadView方法就會被調(diào)用
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末葱绒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子斗锭,更是在濱河造成了極大的恐慌地淀,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岖是,死亡現(xiàn)場離奇詭異帮毁,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)豺撑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門烈疚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人聪轿,你說我怎么就攤上這事胞得。” “怎么了屹电?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長跃巡。 經(jīng)常有香客問我危号,道長,這世上最難降的妖魔是什么素邪? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任外莲,我火速辦了婚禮,結(jié)果婚禮上兔朦,老公的妹妹穿的比我還像新娘偷线。我一直安慰自己,他們只是感情好沽甥,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布声邦。 她就那樣靜靜地躺著,像睡著了一般摆舟。 火紅的嫁衣襯著肌膚如雪亥曹。 梳的紋絲不亂的頭發(fā)上邓了,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天,我揣著相機(jī)與錄音媳瞪,去河邊找鬼骗炉。 笑死,一個胖子當(dāng)著我的面吹牛蛇受,可吹牛的內(nèi)容都是我干的句葵。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼兢仰,長吁一口氣:“原來是場噩夢啊……” “哼乍丈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起旨别,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤诗赌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后秸弛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體铭若,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年递览,在試婚紗的時候發(fā)現(xiàn)自己被綠了叼屠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡绞铃,死狀恐怖镜雨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情儿捧,我是刑警寧澤荚坞,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站菲盾,受9級特大地震影響颓影,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜懒鉴,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一诡挂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧临谱,春花似錦璃俗、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至麦牺,卻和暖如春钮蛛,著一層夾襖步出監(jiān)牢的瞬間鞭缭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工魏颓, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留岭辣,地道東北人。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓甸饱,卻偏偏與公主長得像沦童,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子叹话,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容