iOS應(yīng)用程序的生命周期
iOS應(yīng)用程序一般都是由自己編寫的代碼和系統(tǒng)框架(system frameworks)組成,系統(tǒng)框架提供一些基本infrastructure給所有app來運行,而你提供自己編寫的代碼來定制app的外觀和行為。因此,了解iOS infrastructure和它們?nèi)绾喂ぷ鲗帉慳pp是很有幫助的。
Main函數(shù)入口
所有基于C編寫的app的入口都是main函數(shù),但iOS應(yīng)用程序有點不同。不同就是你不需要為iOS應(yīng)用程序而自己編寫main函數(shù),當(dāng)你使用Xcode創(chuàng)建工程的時候就已經(jīng)提供了。除非一些特殊情況,否則你不應(yīng)該修改Xcode提供的main函數(shù)實現(xiàn)。示例代碼如下:
#import <UIKit/UIKit.h> #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }
上面實例代碼中有一個很重要的函數(shù)UIApplicationMain,它主要是創(chuàng)建app的幾個核心對象來處理以下過程:
- 從可用
Storyboard文件加載用戶界面 - 調(diào)用
AppDelegate自定義代碼來做一些初始化設(shè)置 - 將app放入
Main Run Loop環(huán)境中來響應(yīng)和處理與用戶交互產(chǎn)生的事件
應(yīng)用程序的架構(gòu)
iOS應(yīng)用程序都遵循Model-View-Controller的架構(gòu),Model負(fù)責(zé)存儲數(shù)據(jù)和處理業(yè)務(wù)邏輯,View負(fù)責(zé)顯示數(shù)據(jù)和與用戶交互,Controller是兩者的中介,協(xié)調(diào)Model和View相互協(xié)作。它們的通訊規(guī)則如下:
-
Controller能夠訪問Model和View,Model和View不能互相訪問
MVC Communication - Reference from Stanford University.png
-
當(dāng)
View與用戶交互產(chǎn)生事件時,使用target-action方式來處理
MVC Communication - Reference from Stanford University.png
#p#
-
當(dāng)
View需要處理一些特殊UI邏輯或獲取數(shù)據(jù)源時,通過delegate或data source方式交給Controller來處理
MVC Communication - Reference from Stanford University.png
#p#
-
Model不能直接與Controller通信,當(dāng)Model有數(shù)據(jù)更新時,可以通過Notification或KVO (Key Value Observing)來通知Controller更新View
MVC Communication - Reference from Stanford University.png
了解iOS的MVC設(shè)計模式之后,我們從下圖來了解在MVC模式下iOS應(yīng)用程序有哪些關(guān)鍵對象以及它們職責(zé)主要是什么?

The Structure of an App.png
-
UIApplication對象
用戶與iOS設(shè)備交互時產(chǎn)生的事件(Multitouch Events,Motion Event,Remote Control Event)交由UIApplication對象來分發(fā)給control objects(UIControl)對應(yīng)的target objects來處理并且管理整個事件循環(huán),而一些關(guān)于app運行時重要事件委托給app delegate來處理。 -
App delegate對象
App delegate對象遵循UIApplicationDelegate協(xié)議,響應(yīng)app運行時重要事件(app啟動、app內(nèi)存不足、app終止、切換到另一個app、切回app),主要用于app在啟動時初始化一些重要數(shù)據(jù)結(jié)構(gòu);例如,初始化UIWindow,設(shè)置一些屬性,為window添加rootViewController。 -
View controller對象
View Controller有一個view屬性是view層次結(jié)構(gòu)中的根view,你可以添加子view來構(gòu)建復(fù)雜的view;controller有一些viewDidLoad、viewWillAppear等方法來管理view的生命周期;由于它繼承UIResponder,所有還會響應(yīng)和處理用戶事件。 -
Documents和data model對象
data model對象主要用來存儲數(shù)據(jù)。例如,餓了么app在搜索切換地址后,有歷史記錄搜索地址歷史,當(dāng)app下次啟動時,讀取和顯示搜索地址歷史。
document對象(繼承UIDocument)用來管理一些或所有的data model對象。document對象并不是必須的,但提供一種方便的方式來分組屬于單個文件或多個文件的數(shù)據(jù)。 -
UIWindow對象
UIWindow對象位于view層次結(jié)構(gòu)中的最頂層,它充當(dāng)一個基本容器而不顯示內(nèi)容,如果想顯示內(nèi)容,添加一個content view到window。
它也是繼承UIResponder,所以它也是會響應(yīng)和處理用戶事件。 -
#p#
-
View、control、layer對象
View對象可以通過addSubview和removeFromSuperview 等方法管理view的層次結(jié)構(gòu),使用layoutIfNeeded和setNeedsLayout等方法布局view的層次結(jié)構(gòu),當(dāng)你發(fā)現(xiàn)系統(tǒng)提供view已經(jīng)滿足不了你想要的外觀需求時,可以重寫drawRect方法或通過layer屬性來構(gòu)造復(fù)雜的圖形外觀和動畫。還有一點,UIView也是繼承UIResponder,所以也能夠處理用戶事件。
Control對象通常就是處理特定類型用戶交互的View,常用的有button、switch、text field等。
除了使用View和Control來構(gòu)建view層次結(jié)構(gòu)來影響app外觀之外,還可以使用Core Animation框架的Layer對象來渲染view外觀和構(gòu)建復(fù)雜的動畫。
Main Run Loop
一個iOS應(yīng)用程序的main run loop主要作用是處理所有與用戶相關(guān)的事件。UIApplication對象在啟動時就設(shè)置main run loop和使用它來處理事件和更新基于view的界面。正如它的名字顯示,main run loop是運行在應(yīng)用程序的主線程。這樣就確保與接收到用戶相關(guān)的事件被有序地處理。
下圖顯示main run loop的架構(gòu)和用戶事件最終是怎樣被應(yīng)用程序處理。當(dāng)用戶與設(shè)備交互時,系統(tǒng)就會生成與交互關(guān)聯(lián)的事件,然后被應(yīng)用程序的UIKit通過一個特殊的端口來分發(fā)。應(yīng)用程序把事件放入隊列,然后逐個分發(fā)到main run loop來執(zhí)行。UIApplication對象是***個對象接收到事件,然后決定怎樣處理它。一個touch event通常都被分發(fā)到main window對象,然后依次分發(fā)到發(fā)生觸碰的view。其他event的接收事件對象路徑可能有點不同。

Main Run Loop from Apple Document
大多數(shù)的事件通過使用main run loop來分發(fā),但有些不是。有些事件被發(fā)送到一個delegate對象或傳遞到你提供的block中。想了解更多如何處理大多數(shù)類型的事件,其中包括touch、remote control、motion、accelerometer和gyroscopic等事件,請查閱Event Handle Guide for iOS。
應(yīng)用程序的狀態(tài)和多任務(wù)
有時系統(tǒng)會從app一種狀態(tài)切換另一種狀態(tài)來響應(yīng)系統(tǒng)發(fā)生的事件。例如,當(dāng)用戶按下home鍵、電話打入、或其他中斷發(fā)生時,當(dāng)前運行的應(yīng)用程序會切換狀態(tài)來響應(yīng)。應(yīng)用程序的狀態(tài)有以下幾種:

App State from Apple Document
#p#
- Not running:app還沒運行
- Inactive:app運行在foreground但沒有接收事件
- Active:app運行在foreground和正在接收事件
- Background:運行在background和正在執(zhí)行代碼
- Suspended:運行在background但沒有執(zhí)行代碼
大多數(shù)發(fā)生狀態(tài)轉(zhuǎn)換時都會調(diào)用delegate對象對應(yīng)的方法來響應(yīng)app的狀態(tài)改變。下面匯總了delegate對象的所有方法,當(dāng)app狀態(tài)發(fā)生轉(zhuǎn)換時,你可能會使用到它們。
application:willFinishLaunchingWithOptions:- 這個方法是你在啟動時的***次機會來執(zhí)行代碼application:didFinishLaunchingWithOptions:- 這個方法允許你在顯示app給用戶之前執(zhí)行***的初始化操作applicationDidBecomeActive:- app已經(jīng)切換到active狀態(tài)后需要執(zhí)行的操作applicationWillResignActive:- app將要從前臺切換到后臺時需要執(zhí)行的操作applicationDidEnterBackground:- app已經(jīng)進(jìn)入后臺后需要執(zhí)行的操作applicationWillEnterForeground:- app將要從后臺切換到前臺需要執(zhí)行的操作,但app還不是active狀態(tài)applicationWillTerminate:- app將要結(jié)束時需要執(zhí)行的操作
現(xiàn)在講下app啟動、來回切換app和鎖屏?xí)r狀態(tài)的切換和調(diào)用對應(yīng)哪些delegate對象的方法:
-
app啟動和active/inactive

Launch and active/inactive from Apple WWDC 2011 Session
如圖所示,當(dāng)app啟動時,首先由not running狀態(tài)切換到inactive狀態(tài),此時調(diào)用application:didFinishLaunchingWithOptions:方法;然后由inactive狀態(tài)切換到active狀態(tài),此時調(diào)用applicationDidBecomeActive:方法。
Launch and active/inactive 2 from Apple WWDC 2011 Session
當(dāng)app發(fā)生中斷時,由
active狀態(tài)切換到inactive狀態(tài),此時調(diào)用applicationWillResignActive:方法。 -
來回切換app

Switch from an app from Apple WWDC 2011 Session
#p#
如圖所示,當(dāng)切換到另一個app時,由狀態(tài)active切換到inactive,此時調(diào)用applicationWillResignActive:方法;然后從inactive狀態(tài)切換到running狀態(tài),此時調(diào)用applicationDidEnterBackground:方法。
Switch to an app from Apple WWDC 2011 Session
而當(dāng)切換回本來的app時,由running狀態(tài)切換到inactive狀態(tài),此時調(diào)用applicationWillEnterForeground:方法,然后由inactive狀態(tài)切換到active狀態(tài),調(diào)用applicationDidBecomeActive:方法。 -
鎖屏

Device lock from Apple WWDC 2011 Session
如何所示,當(dāng)手機鎖屏?xí)r,由狀態(tài)active切換到inactive,此時調(diào)用applicationWillResignActive:;然后再由inactive狀態(tài)切換到running狀態(tài),此時調(diào)用applicationDidEnterBackground:方法。更多關(guān)于app狀態(tài)切換以及調(diào)用
app delegate哪些方法,請觀看WWDC 2011 Session的session_320__adopting_multitasking_in_your_app視頻。 -
應(yīng)用程序的終止
系統(tǒng)常常是為其他app啟動時由于內(nèi)存不足而回收內(nèi)存***需要終止應(yīng)用程序,但有時也會是由于app很長時間才響應(yīng)而終止。如果app當(dāng)時運行在后臺并且沒有暫停,系統(tǒng)會在應(yīng)用程序終止之前調(diào)用
applicationWillTerminate:來保存用戶的一些重要數(shù)據(jù)以便下次啟動時恢復(fù)到app原來的狀態(tài)。總結(jié)
本文總結(jié)了iOS應(yīng)用程序從啟動到結(jié)束過程中有哪些關(guān)鍵對象在參與,以及當(dāng)用戶與系統(tǒng)交互時產(chǎn)生事件時,系統(tǒng)利用main run loop來管理事件循環(huán),決定將事件交給系統(tǒng)哪些對象處理和如何處理。而當(dāng)app啟動、來回切換app和鎖屏?xí)r,app的狀態(tài)如何切換和調(diào)用對應(yīng)的哪些
app delegate對象來處理。























