標籤:
iOS程式的啟動執行順序 AppDelegate 及 UIViewController 的生命週期
iOS應用程式的狀態切換很重要,而UIViewControler對於iOS這種MVC模式來說尤為重要,基本都要繼承自他。
一、iOS程式的啟動執行順序
1 程式的入口
進入main函數, 設定AppDelegate稱為函數的代理
2 程式完成載入
-[AppDelegate application:didFinishLaunchingWithOptions:]
3 建立window視窗
4 程式被啟用
-[AppDelegate applicationDidBecomeActive:]
5 當點擊command+H時
程式取消啟用狀態
-[AppDelegate applicationWillResignActive:]
程式進入後台
-[AppDelegate applicationDidEnterBackground:]
6 點擊進入工程
程式進入前台
-[AppDelegate applicationWillEnterForeground:]
程式被啟用
-[AppDelegate applicationDidBecomeActive:]
1、對於applicationWillResignActive(非活動)與applicationDidEnterBackground(後台)這兩個的區別。
(1)applicationWillResignActive(非活動):
比如當有電話進來或簡訊進來,在或者鎖屏等,這時你的應用程式掛起進入非使用中,也就是你的手機其實介面還是顯示著你當前的App視窗,只不過被別的任務強制佔用了,或者後台狀態(因為要先進入非使用中,然後進入後台)。
(2)applicationDidEnterBackground(後台):
指當前視窗不是你的App,大多數程式進入這個後台後會在在這個狀態上停留一會,時間到之後會進入掛起狀態(Suspended)。如果你程式特殊處理後可以長期處於後台狀態即在後台狀態也可以運行。Suspended(掛起):程式在後台不能執行代碼。系統會自動把程式變成這個狀態而且不會發出通知。當掛起時,程式還是停留在記憶體中的,當系統記憶體低時,系統就把掛起的程式清除掉,為前景程式提供更多的記憶體。
看下面流程圖:
這個圖特別重要,說明了所有的切換狀態。
入口函數:
int main(int argc, char * argv[]) { @autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([XYZAppDelegate class]));
} }
2.UIApplicationMain 函數解釋:
官方解釋
// 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);
翻譯過來之後(參數的解釋)
1.argc和argv參數是為了與C語言保持一致,在這沒用到,不詳述。
2.後面兩個參數為principalClassName(主要類名)和delegateClassName(委託類名)。
(1)如果principalClassName是nil,那麼它的值將從Info.plist中擷取,如果Info.plist中沒有,則預設為UIApplication。principalClass這個類除了管理整個程式的生命週期之外什麼都不做,它只負責監聽事件然後交給delegateClass去做。
(2)delegateClass將在工程建立時執行個體化一個對象。NSStringFromClass([AppDelegate class]) //相當於@"AppDelegate"
3.AppDelegate類實現檔案
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOption{// Override point for customization after application launch. NSLog(@"didFinishLaunchingWithOptions"); return YES;}- (void)applicationWillResignActive:(UIApplication *)application { /* 當應用程式從活動狀態(active)變到非使用中(inactive時被觸發調用, 這可能發生在一些臨時中斷下(例如:來電話、來簡訊)又或者程式退出時,他會先過渡到後台然後terminate 使用這方法去暫停進行中的任務,禁用計時器,節流OpenGL ES 幀率。在遊戲中應該在這個方法裡面暫停遊戲。 */ // 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 throttle down OpenGL ES frame rates. Games should use this method to pause the game. NSLog(@"WillResignActive");}- (void)applicationDidEnterBackground:(UIApplication *)application { /* 使用這種方法來釋放共用資源,儲存使用者資料,無效計時器,儲存足夠多的應用程式狀態資訊來恢複您的應用程式的目前狀態,以防它終止遺失資料。 如果你的程式支援後台運行,那麼當使用者退出時不會調用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. NSLog(@"DidEnterBackground"); }- (void)applicationWillEnterForeground:(UIApplication *)application { /* 先從後台切換到非使用中,然後進入活動狀態。 */ // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. NSLog(@"WillEnterForeground");}- (void)applicationDidBecomeActive:(UIApplication *)application { /* 重啟所有的任務,不管是從非使用中還是剛啟動程式,還是後台狀態。 */ // 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. NSLog(@"DidBecomeActive"); }- (void)applicationWillTerminate:(UIApplication *)application { /* 終止,game over */ // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. NSLog(@"WillTerminate");}
下面給出列印就明白他們之間的互動先後順序了:
啟動程式
2014-07-28 15:22:39.883 LifeCycle[3024:a0b] didFinishLaunchingWithOptions
2014-07-28 15:22:39.887 LifeCycle[3024:a0b] DidBecomeActive
按下Home鍵
2014-07-28 15:22:43.130 LifeCycle[3024:a0b] WillResignActive
2014-07-28 15:22:43.131 LifeCycle[3024:a0b] DidEnterBackground
重新點擊程式
2014-07-28 15:22:44.380 LifeCycle[3024:a0b] WillEnterForeground
2014-07-28 15:22:44.380 LifeCycle[3024:a0b] DidBecomeActive
分析:
1.application:didFinishLaunchingWithOptions:
程式首次已經完成啟動時執行,若直接啟動,launchOptions中沒有資料;否則,launchOptions將包含對應方式的內容(比如從中啟動節奏大師--)。
2.applicationWillResignActive(非活動)
程式將要失去Active狀態時調用,比如按下Home鍵或有電話資訊進來。之後程式將進入後台狀態。對應的applicationWillEnterForeground這個方法用來
a、暫停正在執行的任務;
b、禁止計時器;
c、減少OpenGL ES幀率;
d、若為遊戲應暫停遊戲;
3.applicationDidEnterBackground(已經進入後台)
程式已經進入後台時調用,對應applicationDidBecomeActive(已經變成前台),這個方法用來
a、釋放共用資源;
b、儲存使用者資料(寫到硬碟);
c、作廢計時器;
d、儲存足夠的程式狀態以便下次恢複;
4.applicationWillEnterForeground(將進入前台)
程式即將進去前台時調用,對應applicationWillResignActive(將進入後台)。這個方法用來
1.撤銷applicationWillResignActive中做的改變。
5.applicationDidBecomeActive(已經進入前台)
程式已經變為Active(前台)時調用。對應applicationDidEnterBackground(已經進入後台)。
1.若程式之前在後台,在此方法內重新整理使用者介面。
6.applicationWillTerminate
程式即將退出時調用。記得儲存資料,如applicationDidEnterBackground方法一樣。
其實仔細看上面那個狀態圖和輸出列印,他說明了所有這些切換互動流程。
二、UIViewController的生命週期
//The designated initializer //這個UIViewController的指定初始化方法(其他的初始化方法最終要調用這個初始化方法); //如果串連了串聯圖storyBoard根本就不用管這貨- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { NSLog(@"%s", __FUNCTION__); self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization } return self; } //視圖控制器中的視圖載入完成,viewController內建的view載入完成- (void)viewDidLoad { NSLog(@"%s", __FUNCTION__); [super viewDidLoad]; // Do any additional setup after loading the view.}//出現記憶體警告 //類比記憶體警告:點擊模擬器->hardware-> Simulate Memory Warning- (void)didReceiveMemoryWarning { NSLog(@"%s", __FUNCTION__); [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.}//視圖將要出現- (void)viewWillAppear:(BOOL)animated { NSLog(@"%s", __FUNCTION__); [super viewWillAppear:animated];}//視圖已經出現- (void)viewDidAppear:(BOOL)animated { NSLog(@"%s", __FUNCTION__); [super viewDidAppear:animated];}//視圖將要消失 //雙擊Home鍵,向上推出程式執行該函數- (void)viewWillDisappear:(BOOL)animated { NSLog(@"%s", __FUNCTION__); [super viewWillDisappear:animated];}//視圖已經消失- (void)viewDidDisappear:(BOOL)animated { NSLog(@"%s", __FUNCTION__); [super viewDidDisappear:animated];}@end
看列印輸出:
2015-01-03 17:39:03.973 LessonUIViewControler[791:41458] -[RootViewController initWithNibName:bundle:]
2015-01-03 17:39:03.976 LessonUIViewControler[791:41458] -[RootViewController viewDidLoad]
2015-01-03 17:39:03.976 LessonUIViewControler[791:41458] -[RootViewController viewWillAppear:]
2015-01-03 17:39:04.071 LessonUIViewControler[791:41458] -[RootViewController viewDidAppear:]
2015-01-03 17:39:11.630 LessonUIViewControler[791:41458] Received memory warning.
2015-01-03 17:39:11.631 LessonUIViewControler[791:41458] -[RootViewController didReceiveMemoryWarning]
2015-01-03 17:39:17.581 LessonUIViewControler[791:41458] -[RootViewController viewWillDisappear:]
2015-01-03 17:39:17.581 LessonUIViewControler[791:41458] -[RootViewController viewDidDisappear:]
當一個視圖控制器被建立,並在螢幕上顯示的時候。 代碼的執行順序
1、alloc 建立對象,分配空間;
2、init (initWithNibName) 初始化對象,初始化資料;
3、loadView 從nib載入視圖 ,通常這一步不需要去幹涉。除非你沒有使用xib檔案建立視圖;
4、viewDidLoad 載入完成,可以進行自訂資料以及動態建立其他控制項;
5、viewWillAppear 視圖將出現在螢幕之前,馬上這個視圖就會被展現在螢幕上了;
6、viewDidAppear 視圖已在螢幕上渲染完成 當一個視圖被移除螢幕並且銷毀的時候的執行順序,這個順序差不多和上面的相反;
1、viewWillDisappear
視圖將被從螢幕上移除之前執行
2、viewDidDisappear
視圖已經被從螢幕上移除,使用者看不到這個視圖了
3、dealloc
視圖被銷毀,此處需要對你在init和viewDidLoad中建立的對象進行釋放 關於viewDidUnload :在發生記憶體警告的時候如果本視圖不是當前螢幕上
正在顯示的視圖的話,
viewDidUnload將會被執行,本視圖的所有子視圖將被銷毀,以釋放記憶體,此時開發人員需要手動對viewLoad、viewDidLoad中建立 的對象釋放記憶體。
因為當這個視圖再次顯示在螢幕上的時候,viewLoad、viewDidLoad 再次被調用,以便再次構造視圖。 當我們建立一個UIViewController類的對
象時,通常系統會產生幾個預設的方法,這些方法大多與視圖的調用有關,但是在視圖調用時,這些方法的調用順序如何,需要整理下。 通常上
述方法包括如下幾種,這些方法都是UIViewController類的方法:
- (void)viewDidLoad;
- (void)viewDidUnload;
- (void)viewWillAppear:(BOOL)animated;
- (void)viewDidAppear:(BOOL)animated;
- (void)viewWillDisappear:(BOOL)animated;
- (void)viewDidDisappear:(BOOL)animated;
下面介紹下APP在運行時的調用順序。
1)- (void)viewDidLoad; 一個APP在載入時會先通過調用loadView方法或者載入IB中建立的初始介面的方法,將視圖載入到記憶體中。然後會
調用viewDidLoad方法來進行進一步的設定。通常,我們對於各種初始資料的載入,初始設定等很多內容,都會在這個方法中實現,所以這個方法是
一個很常用,很重要的方法。
但是要注意,這個方法只會在APP剛開始載入的時候調用一次,以後都不會再調用它了,所以只能用來做初始設定。
2) - (void)viewDidUnload;在記憶體足夠的情況下,軟體的視圖通常會一直儲存在記憶體中,但是如果記憶體不夠,一些沒有正在顯示的viewcontroller就
會收到記憶體不夠的警告,然 後就會釋放自己擁有的視圖,以達到釋放記憶體的目的。但是系統只會釋放記憶體,並不會釋放對象的所有權,所以通常我們
需要在這裡將不需要在記憶體中保留的對象釋 放所有權,也就是將其指標置為nil。 這個方法通常並不會在視圖變換的時候被調用,而只會在系
統退出或者收到記憶體警告的時候才會被調用。但是由於我們需要保證在收到記憶體警告的時候能夠對其作出反應,所以這個方法通常我們都需要去實現。
另外,即使在裝置上按了Home鍵之後,系統也不一定會調用這個方法,因為IOS4之後,系統允許將APP在後台掛起,並將其繼續滯留在記憶體中,因此,
viewcontroller並不會調用這個方法來清除記憶體。
3)- (void)viewWillAppear:(BOOL)animated;系統在載入所有資料後,將會在螢幕上顯示視圖,這時會先調用這個方法。通常我們會利用這個方法,
對即將顯示的視圖做進一步的設定。例如,我們可以利用這個方法來設定裝置不同方向時該如何顯示。 另外一方面,當APP有多個視圖時,在
視圖間切換時,並不會再次載入viewDidLoad方法,所以如果在調入視圖時,需要對資料做更新,就只能在這個方法內實現了。所以這個方法也非常常用。
4) - (void)viewDidAppear:(BOOL)animated;
有時候,由於一些特殊的原因,我們不能在viewWillApper方法裡,對視圖進行更新。那麼可以重寫這個方法,在這裡對正在顯示的視圖進行進一步的設定。
5) - (void)viewWillDisappear:(BOOL)animated;
在視圖變換時,當前視圖在即將被移除、或者被覆蓋時,會調用這個方法進行一些善後的處理和設定。
由於在IOS4之後,系統允許將APP在後台掛起,所以在按了Home鍵之後,系統並不會調用這個方法,因為就這個APP本身而言,APP顯示的view,仍是掛起時候
的view,所以並不會調用這個方法。
6) - (void)viewDidDisappear:(BOOL)animated;
我們可以重寫這個方法,對已經消失,或者被覆蓋,或者已經隱藏了的視圖做一些其他動作。 上述方法的流程圖可以簡單用如下表示:
運行APP —> 載入視圖 —> 調用viewDidLoad方法 —> 調用viewWillAppear方法 —> 調用viewDidAppear方法 —> 正常運行
iOS程式執行順序 AppDelegate及 UIViewController 的生命週期