加入RUN!PC粉絲團
最近新增的精選文章
 
最多人點閱的精選文章
 
 
精選文章 - 開發技術
分享到Plurk
分享到FaceBook
 
iOS程式開發與XCode 4.X-iOS應用程式的生命週期(下)
文‧圖/何孟翰 2012/3/16 下午 03:34:30

當然也有些應用程式可以持續的在背景執行,例如持續的撥放音效等等。同時,也有些應用程式一開始就可以在背景執行,就會直接進入這個狀態而不是在前景執行。如同一開始提到的,只有iOS4之後的裝置才能有這個狀態,而在之前的裝置就會直接終止,而回到沒有執行,也就是一開始的狀態。

而這個背景執行之後就會進入不執行應用程式的狀態,iOS作業系統會在適當時候將應用程式移到這個狀態。而這個應用程式基本上就是冷凍在當時的狀態,而不會再執行任何的程式碼。如果記憶體過低時,系統會競自刪除這些暫時中止的應用程式,也就是說不會通知使用者,而就將記憶體釋放出來給前景的應用程式使用。

因此當我們討論到這裡,你可以想像一般的應用程式大概就會有【未執行】【正在執行】和【暫時中止】這三種主要的狀態。而接下來回到了委任的實作類別,我們就會討論這些狀態交互作用的影響。
應用程式的執行
應用程式會因為被呼叫而起動。這種被呼叫可能是如同圖5,被一個點擊起動,也有可能是被其它的應用程式呼叫起來。總之,這個應用程式會從一般的未執行,也就是在記憶體中不佔任何空間,到載入的啟動狀態或者是進入背景狀態。
在一開始應用程式執行之初,它會試著載入主要的nib,並且啟動委任物件,並且會先初始化應用程式並且將應用程式進入前景如圖9。



▲ 圖9 將應用程式進入前景



因此讓我們作如下的實驗,請你在AppDelegate.m中的函數
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions中return YES之前加入如下的敘述
NSLog(@"初始化完成");
而在- (void)applicationDidBecomeActive:(UIApplication *)application中加入如下的敘述:
NSLog(@"進入前景準備接受使用者的命令");

如此當你執行完,你可以在偵錯畫面看到如圖10的畫面。


▲ 圖10 執行的結果



因此我們可以將適當的初始化程序填入這兩個函數之中。

應用程式進入背景執行
應用程式進入前景並且進入了可活動的狀態,就可以接收使用者的輸入。然而此時如果使用者按下了Home按鈕,或者其它的應用程式被執行起來,正在前景的這個應用程式會進入非前景的狀態接著進入背景的狀態。
雖然說時間很短,但是當使用者按下Home按鈕,或者其它的應用程式運行時,你可以看到如下的程序applicationWillResignActive:被啟動,因此你可以在它底下增加一行敘述:
NSLog(@"這個應用程式要離開前景了");

而在applicationDidEnterBackground時,請你加入如下的敘述:
NSLog(@"進入背景,即將中止執行");

如此執行的結果,你可以看到它們依序的執行如下



▲ 圖11 進入背景的呼叫次序



應用程式進入背景之後大概只有五秒執行該函數,所以如果需要較長時間,應用程式就會從記憶體中直接被刪除,所以我們應該要儘快的使用return傳回。所以如果有任何使用者介面相關的函數,都應該在這個函數之前完成。因此在這個函數中,我們比較常用來儲存使用者的資料,這樣當它被從記憶體中移除也不用擔心。

因此所有的多工應用程式都應該在進入背景時自己負責作這種狀態維持的工作,不管是短暫進入背景,或者會在背景執行。在背景這段時間,你的所有物件都依然存在於記憶體中供你使用。例如我們所熟知的Controller物件,window物件和其它的View。然而,系統為了節省記憶體,會有一些其它的方式來釋放不需要的記憶體,例如跟動畫有關的Core Animation物件,以及為了增進效能所快取的影像,與其它資料的快取等等。

應用程式回應中斷事件
在應用程式執行中,有時會碰到一些被中斷的情形,例如有電話打來,接收簡訊,告知的訊息,或者是行事曆的告知,應用程式會暫時移入非活動的狀態。也就是說,在使用者作出要接收或者是忽略這個事件之前,iOS是不會讓這個應用程式接收使用者的回應的。因此,如果使用者按下忽略,會重新進入活動的狀態,而如果使用者選擇接聽電話,或者是進入簡訊或行事曆,則會進入背景執行的狀態。你可以觀察如圖12。



▲ 圖12 回應短暫的應用程式中斷



如果使用者是接收電話,當打完後掛斷,會回到原先的應用程式,也就是說,這個應用程式會再被啟動。而當使用者是按下Home按鈕並且執行了其它的應用程式,這個應用程式就不會被啟動。

回應回到前景的執行
因此,在應用程式的執行時,使用者按下這個應用程式可能有兩個狀態,一個是第一次執行,而第二次是從背景回到前景,因此,當第二次運行時,系統會呼叫applicationWillEnterForeground:,為了實驗這個部份,我們可以在這個函數中加入如下的敘述:
NSLog(@"應用程式即將回到前景執行");

因此,讓我們重新執行一個應用程式,按下Home將它移至背景,再按下這個應用程式將它移回前景,則可以看到如圖13的結果。



▲ 圖13 應用程式呼叫的delegate函數



回應應用程式的中斷
雖然說應用程式通常是移到背景被中止執行,但有時應用程式還是會進入結束的狀態。例如應用程式是用iOS3.X之前連結的,或者是被部署到3之前的版本,或者是現在的這個裝置不被支援多功。
而當我們的應用程式不管是在前景或背景執行,而要被中斷且從記憶體中移除時,會呼叫應用程式delegate的applicationWillTerminate:函數,此時我們可以作一些記憶體清除與整理的動作,同時也可以儲存使用者的資料或者應用程式的狀態,這樣在下一次執行時就可以重新啟動。這個函數一般也會有五秒鐘來執行,如果超過這個時間,就會直接被iOS系統移除。

設計沒有背景執行的應用程式
有的時候,多工的環境會讓系統變得複雜,此時如果要能夠在多工的環境實現單工,也就是說讓它能夠不進入背景,你可以在Info.plist中輸入如下的指令:
UIApplicationExitsOnSuspend
並且將它設定為true,這樣就可以在使用者按下Home或者是程式結束後直接從記憶體移除而不進入多工。
結語
在iOS 3.X之前,應用程式的周期是很簡單的,只有按下,執行,結束與低記憶體的警告等等,而在iOS4之後,這些情境是必須要好好理解的。在筆者的iOS課程與一些輔導的過程,與學員的互動時,常常會碰到學員有如下的疑問,某某應用程式一開始執行正常,但是第二次進入會發生錯誤,通常就是這些生命週期並沒有完善的管理。既然iOS能夠保持使用者流暢的體驗,身為開發者的我們,也應該要依照著它們設計的常規,來設計出符合iOS規範的應用程式。