前言
網上有很多關於程式啟動過程和UIApplicationDelegate方法呼叫順序的文章。筆者這裡不再介紹程式的啟動過程和delegate方法的呼叫過程。而是介紹一下UIApplication會在什麼情況下呼叫UIApplicationDelegate的哪些方法。以及常見的場景下,哪些方法會被呼叫,蘋果為什麼會這樣做。
回顧
首先讓我們先來回顧下與程式啟動過程相關的一些delegate方法的呼叫時機。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSLog(@"程式啟動完成:%s",__func__); return YES; } - (void)applicationDidBecomeActive:(UIApplication *)application { NSLog(@"已經獲得焦點:%s",__func__); } - (void)applicationWillResignActive:(UIApplication *)application { NSLog(@"將要釋放焦點:%s",__func__); } - (void)applicationDidEnterBackground:(UIApplication *)application { NSLog(@"已經進入後臺:%s",__func__); } - (void)applicationWillEnterForeground:(UIApplication *)application { NSLog(@"將要進入前臺:%s",__func__); } - (void)applicationWillTerminate:(UIApplication *)application { NSLog(@"程式將要退出:%s",__func__); } |
情景一 程式啟動
程式被載入到記憶體,完成啟動,application物件會自動呼叫delegate的下面這個方法,證明程式已經啟動完成
。所以這個方法也是首先會被application回撥的方法,且這個方法在整個程式的生命週期中只會被呼叫一次。
1 |
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions; |
程式啟動時,回撥完上面的方法,會繼續回撥delegate的已經獲得了焦點的方法,證明程式已經獲得了焦點
。
1 |
- (void)applicationDidBecomeActive:(UIApplication *)application; |
結論:應用啟動過程中,會依次呼叫delegate已經啟動完成和已經獲得焦點的方法,不會呼叫已經進入前臺的方法。
情景二 程式從前臺退出到後臺
當程式處於前臺時,單擊home鍵,程式會自動退出到後臺。在這個過程中,程式會先回撥delegate的將要失去焦點的方法,證明程式將要失去焦點
。
1 |
- (void)applicationWillResignActive:(UIApplication *)application; |
呼叫呼叫完上面的方法後,程式緊接著會呼叫delegate已經進入後臺的方法,證明程式已經進入後臺
。
1 |
- (void)applicationDidEnterBackground:(UIApplication *)application; |
結論:單擊home鍵進入後臺會依次呼叫delegate的將要失去焦點的方法和已經進入後臺的方法。
情景三 程式從後臺進入到前臺
(4)從後臺進入前臺(無論是雙擊home鍵進入或者點選應用圖示進入),會回撥delegate的將要進入前臺方法,證明程式將要進入前臺
。
1 |
- (void)applicationWillEnterForeground:(UIApplication *)application; |
回撥完上面的方法,緊接著會繼續回撥delegate的已經獲得焦點的方法,證明程式已經獲得了焦點
。
1 |
- (void)applicationDidBecomeActive:(UIApplication *)application; |
結論:從後臺進入前臺,會依次呼叫delegate的將要進入前臺和已經獲得焦點的方法。
情景四 雙擊home鍵切換程式
在前臺,雙擊home鍵,只會呼叫delegate的將要失去焦點的方法,證明程式將要失去焦點
。
1 |
- (void)applicationWillResignActive:(UIApplication *)application; |
當使用者真正切換應用時候,才會繼續呼叫delegate的已經進入後臺的方法,證明程式已經進入後臺
。
1 |
- (void)applicationDidEnterBackground:(UIApplication *)application; |
結論:雙擊home鍵切換應用。會分別呼叫程式將要失去焦點的方法和程式已經進入後臺的方法。 且這兩個方法是分開呼叫的。即,雙擊home鍵時呼叫將要失去焦點的方法,選擇其他應用時呼叫已經進入後臺的方法。
情景五 在前臺雙擊home鍵殺死程式
雙擊home鍵時,只會呼叫delegate的將要失去焦點的方法(上面已經說過),證明程式將要失去焦點。
1 |
- (void)applicationWillResignActive:(UIApplication *)application; |
然後手指上滑殺死程式,會直接呼叫delegate的已經進入後臺的方法,證明程式已經進入後臺。
1 |
- (void)applicationDidEnterBackground:(UIApplication *)application; |
然後緊接著呼叫delegate的程式將要退出的方法,證明程式將要被殺死。
- (void)applicationWillTerminate:(UIApplication *)application;
結論:雙擊home鍵然後殺死程式,會按照如下順序呼叫delegate的方法:
1 - (void)applicationWillResignActive:(UIApplication *)application;(雙擊home鍵呼叫)
12 - (void)applicationDidEnterBackground:(UIApplication *)application;(殺死程式時呼叫這兩個方法)- (void)applicationWillTerminate:(UIApplication *)application;
情景六 從其他程式前臺雙擊home鍵殺死後臺程式
如果從其他程式的前臺,雙擊home鍵殺死後臺程式,被殺死程式只會回撥delegate即將退出的方法。
1 |
- (void)applicationWillTerminate:(UIApplication *)application; |
為什麼呢?
因為我們是從一個前臺程式殺死一個後臺程式,這個後臺程式當初進入後臺時候已經呼叫了將要釋放焦點和已經進入後臺的方法,所以殺死時候只會回撥delegate即將終結的方法。
結論:從一個前臺程式殺死一個後臺程式。後臺程式只會回撥delegate的程式即將退出的方法。
情景七 下拉通知欄
下拉通知欄,只會回撥delegate的程式將要釋放焦點的方法。程式並沒有進入後臺,所以不會呼叫進入後臺的方法
1 |
- (void)applicationWillResignActive:(UIApplication *)application; |
結論:下拉狀態列只會讓程式失去焦點,並不會讓程式進入後臺。
因為下拉通知欄只呼叫了將要釋放焦點的方法,沒有呼叫進入後臺方法,所以收起通知欄時,只會呼叫已經獲得焦點的方法,不會呼叫進入前臺的方法。
1 |
- (void)applicationDidBecomeActive:(UIApplication *)application; |
同樣,從螢幕下方向上滑動螢幕,喚出工具欄時候,也只會呼叫delegate的將要釋放焦點的方法。收起工具欄時,只會呼叫delegate的已經獲得焦點的方法。
結論:下拉通知欄或者上拉工具欄,都只是回撥delegate的即將釋放焦點的方法,程式不會進入後臺。
為什麼
當初學習iOS時候,對這個地方不是很清楚,總是搞不懂為什麼程式的delegate有一個將要進入前臺的方法applicationWillEnterForeground:
,卻沒有類似於applicationDidEnterForeground:
的已經進入前臺的方法(純屬捏造)?為什麼程式的delegate有一個已經進入後臺的方法applicationDidEnterBackground:
卻沒有一個類似於applicationWillEnterBackground:
的將要進入後臺的方法?為什麼進入前臺時,方法的呼叫順序是applicationWillEnterForeground:
和applicationDidBecomeActive:
而不是相反?這些問題一直困擾著我。
將要進入前臺、已經獲得焦點、將要失去焦點、已經進入後臺這幾個方法是比較容易混淆的,且呼叫順序經常被搞混。但是如果理解了蘋果為什麼這麼設計,這些困惑都將迎刃而解。重點來了:如果一個應用程式失去焦點那麼意味著使用者當前無法進行互動操作,正因如此,程式從前臺退出到後臺時候,一般會先失去焦點再進入後臺避免進入後臺過程中使用者還可以和程式進行互動。同理,一個應用程式從後臺進入前臺也是類似的,會先進入前臺再獲得焦點,這樣進入前臺過程中未完全準備好的情況下使用者無法操作,保證了程式的安全性。
至於為什麼蘋果沒有提供類似於applicationDidEnterForeground:
的已經進入前臺的方法,那是因為程式進入前臺後必定會回撥delegate的已經獲得焦點的方法,所以applicationDidBecomeActive:
方法從本質上就相當於我們想象中的applicationDidEnterForeground:
,如果我們想要在程式進入前臺後做什麼操作,完全可以把這些操作寫到applicationDidBecomeActive:
裡。同理,applicationWillResignActive:
就相當於我們想象中的applicationWillEnterForeground:
。
另外一般如果應用程式要儲存使用者資料會在程式將要失去焦點的方法中進行 (而不是在已經進入後臺的方法中執行),因為如果使用者雙擊Home不會進入後臺只會登出啟用。同理,如果使用者恢復應用狀態一般在已經獲的焦點的方法中執行(而不是在將要進入前臺的方法中執行)。
PS:如非特別說明,所有文章均為原創作品,著作權歸作者所有,轉載請聯絡作者獲得授權,並註明出處,所有打賞均歸本人所有!
如果您是iOS開發者,或者對本篇文章感興趣,請關注本人,後續會更新更多相關文章!敬請期待!