天天看點

iOS——關于應用程式生命周期問題

開發應用程式都要了解其生命周期,今天我們接觸一下iOS應用程式的生命周期。

Main 函數入口

應用程式啟動的時候會執行main 函數,而main函數裡面執行了UIApplicationMain函數。UIApplicationMain函數執行完主要做了以下幾個操作:

(1)建立應用程式UIApplication 對象

(2)建立了應用程式代理對象。預設的應用程式代理對象是AppDelegate。

(3)建立一個事件循環RunLoop。用來實時監測應用程式中的各種事件(觸摸,晃動,遠端控制事件,通知,觀察者,timer 等)

main

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

UIApplicationMain函數有四個參數,你不需要改變這些參數值,不過我們也需要了解這些參數和程式是如何開始的

argc 和argv參數包含了系統帶過來的啟動時間。 第三個參數确定了主要應用程式類的名稱,這個參數指定為nil,這樣UIKit就會使用預設的程式類UIApplication。第四個參數是程式自定義的代理類名,這個類負責系統和代碼之間的互動。它一般在Xcode建立項目時會自動生成。

另外 UIApplicationMain函數加載了程式主界面的檔案。雖然這個函數加載了界面檔案,但是沒有放到應用程式的windows上,你需要在Delegate的 application:willFinishLaunchingWithOptions方法中加載它。

一個應用程式可以有一個主的storyboard檔案或者有一個主的nib檔案,但不能同時有兩個存在。

如果程式在啟動時沒有自動加載主要的故事版或nib檔案,你可以在application:willFinishLaunchingWithOptions方法裡準備windows的展示。

各個程式運作狀态時代理的回調

// 告訴代理程序啟動但還沒進入狀态儲存
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSLog(@"%s,%d",__func__,__LINE__);
    return YES;
}
// 當應用程式啟動時執行,應用程式啟動入口,隻在應用程式啟動時執行一次。若使用者直接啟動,lauchOptions内無資料,若通過其他方式啟動應用,lauchOptions包含對應方式的内容。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSLog(@"%s,%d",__func__,__LINE__);   
    return YES;
}

//在應用程式将要由活動狀态切換到非活動狀态時候,要執行的委托調用,如 按下 home 按鈕,傳回主螢幕,或全屏之間切換應用程式等。
當應用程式将要入非活動狀态執行,在此期間,應用程式不接收消息或事件,比如來電話了
- (void)applicationWillResignActive:(UIApplication *)application {
    NSLog(@"%s,%d",__func__,__LINE__);
}
// 當應用程式入活動狀态執行,這個剛好跟上面那個方法相反
- (void)applicationDidBecomeActive:(UIApplication *)application {
    NSLog(@"%s,%d",__func__,__LINE__);
}

// 當程式被推送到背景的時候調用。是以要設定背景繼續運作,則在這個函數裡面設定即可
- (void)applicationDidEnterBackground:(UIApplication *)application {
    NSLog(@"%s,%d",__func__,__LINE__);
}
// 當程式從背景将要重新回到前台時候調用,這個剛好跟上面的那個方法相反。
- (void)applicationWillEnterForeground:(UIApplication *)application {
    NSLog(@"%s,%d",__func__,__LINE__);
}

// 當程式将要退出是被調用,通常是用來儲存資料和一些退出前的清理工作。這個需要要設定UIApplicationExitsOnSuspend的鍵值。
- (void)applicationWillTerminate:(UIApplication *)application {
    NSLog(@"%s,%d",__func__,__LINE__);
}
// 當程式載入後執行
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
    NSLog(@"%s,%d",__func__,__LINE__);
}
           

啟動:

willFinishLaunchingWithOptions
didFinishLaunchingWithOptions
applicationDidBecomeActive
           

按下home 鍵

// 先進入非活躍狀态
applicationWillResignActive
// 再進入背景
applicationDidEnterBackground
           

輕按兩下Home 鍵,再次打開程式

// 先進入前台
applicationWillEnterForeground
// 再進入活躍狀态
applicationDidBecomeActive
           

使用注意:

一.響應中斷

1.當一個基于警告式的中斷發生時,比如有電話打進來了,這是程式會臨時進入inactive狀态,這使用者可以選擇如何處理這個中斷,流程如下圖:

iOS——關于應用程式生命周期問題

在iOS5,通知不會把程式變成為激活狀态,通知會顯示在狀态欄上,如果你;拉下狀态欄,程式會變成inactive,把狀态欄放回去,程式變回active。

按鎖屏鍵也是另外一種程式的中斷,當你按下鎖屏鍵,系統屏蔽了所有觸摸事件,把app放到了背景,這時app狀态是 inactive,并進入背景。

2.當有這些中斷時,我們的app該怎麼辦呢?我們應該在applicationWillResignActive:方法中:

停止timer 和其他周期性的任務

停止任何正在運作的請求

暫停視訊的播放

如果是遊戲那就暫停它

減少OpenGL ES的幀率

挂起任何分發的隊列和不重要的操作隊列(你可以繼續處理網絡請求或其他時間敏感的背景任務)。

二、應用程式進入背景

// 先進入非活躍狀态

applicationWillResignActive

// 再進入背景

applicationDidEnterBackground

進入背景app 的狀态

當一個 iOS 應用被送到背景,它的主線程會被暫停。用 NSThread 的 detachNewThreadSelector:toTar get:withObject:類方法建立的線程也被挂起了。

進入背景操作

1. 儲存使用者資料或狀态資訊,所有沒寫到磁盤的檔案或資訊,在進入背景時,最後都寫到磁盤去,因為程式可能在背景被殺死,
2. 釋放盡可能釋放的記憶體
           

注意:

applicationDidEnterBackgound: 方法有大概5秒的時間讓你完成這些任務。如果超過時間還有未完成的任務,你的程式就會被終止而且從記憶體中清除。如果還需要長時間的運作任務,可以調用 beginBackgroundTaskWithExpirationHandler 方法去請求背景運作時間和啟動線程來運作長時間運作的任務。

應用程式在背景時的記憶體使用:

在背景時,每個應用程式都應該釋放最大的記憶體。系統努力的保持更多的應用程式在背景同時 運作。不過當記憶體不足時,會終止一些挂起的程式來回收記憶體,那些記憶體最大的程式首先被終止。

事實上,應用程式應該的對象如果不再使用了,那就應該盡快的去掉強引用,這樣編譯器可以回收這些記憶體。如果你想緩存一些對象提升程式的性能,你可以在進入背景時,把這些對象去掉強引用。

下面這樣的對象應該盡快的去掉強引用:

圖檔對象
你可以重新加載的 大的視訊或資料檔案
任何沒用而且可以輕易建立的對象
           

注意:

在背景時,為了減少程式占用的記憶體,系統會自動在回收一些系統幫助你開辟的記憶體。比如:

系統回收Core Animation的後備存儲。

去掉任何系統引用的緩存圖檔

去掉系統管理資料緩存強引用

三、背景傳回前台

當app處于挂起狀态時,它是不能執行任何代碼的。是以它不能處理在挂起期間發過來的通知,比如方向改變,時間改變,設定的改變還有其他影響程式展現的或狀态的通知。在程式傳回背景或前台是,程式都要正确的處理這些通知。

四、程式終止applicationWillTerminate

程式隻要符合以下情況之一,隻要進入背景或挂起狀态就會終止:

iOS4.0以前的系統

app是基于iOS4.0之前系統開發的。

裝置不支援多任務

在Info.plist檔案中,程式包含了 UIApplicationExitsOnSuspend 鍵。

注意:

app如果終止了 ,系統會調用app的代理的方法 applicationWillTerminate: 這樣可以讓你可以做一些清理工作。你可以儲存一些資料或app的狀态。這個方法也有5秒鐘的限制。逾時後方法會傳回程式從記憶體中清除。

注意:使用者可以手工關閉應用程式。’

應用程式進入背景後什麼時候被銷毀?

根據蘋果文檔中關于背景執行的描述,任何app都有10分鐘左右的背景任務執行時間。 10分鐘後,app會被iOS強行挂起。

這是由iOS系統管理決定的,但APP退出在背景後,隻有10秒的持續運作時間,然後暫停。但該APP還在記憶體中,當出現記憶體警告,也就是别的APP要運作,而此時記憶體又不足的情況下,系統會回收停在背景APP所占用的記憶體。如果出現這種情況,那麼你再次打開你的APP,就會重新啟動。

iOS APP類型:

1. 儲存現場。按下Home鍵10秒内直接殺死程序,并釋放記憶體。

2. iOS支援的“多任務”。按下Home鍵轉入多任務狀态,保留在記憶體中,但隻能系統允許的動作:比如GPS,比如VoIP,比如音樂等等。

3. 真正的桌面級别的多任務。隻有Safari/Mail是,蘋果嫡系大都都不是。這個級别的app在背景沒有任何限制動作。

無限制動作的程式,會在使用者無察覺的情況下耗光電力,并且有安全上面的問題(那些在背景依舊默默發送你的個人消息程式)

順便提一句,後兩種占用記憶體的app,也會在任意時間從記憶體中被砍掉,取決于你是否動用了其它app而導緻記憶體不足。

真正不會被砍掉的背景,隻有蘋果那個通知系統。

那對于一些app 需要實作背景運作的操作, 如何實作背景運作呢,請看

http://blog.csdn.net/ci915194561/article/details/50134685