1. 程式人生 > >iOS應用程式的生命週期及前後臺切換,應用的各種狀態)

iOS應用程式的生命週期及前後臺切換,應用的各種狀態)

一、iOS應用程式狀態機一共有五種狀態:

  1. Not running(未執行):應用還沒有啟動,或者應用正在執行但是途中被系統停止。

  2. Inactive(未啟用):當前應用正在前臺執行,但是並不接收事件(當前或許正在執行其它程式碼)。一般每當應用要從一個狀態切換到另一個不同的狀態      時,中途過渡會短暫停留在此狀態。唯一在此狀態停留時間比較長的情況是:當用戶鎖屏時,或者系統提示使用者去響應某些(諸如電話來電、有未讀簡訊等)事件的時候。

  3. Active(啟用狀態):當前應用正在前臺執行,並且接收事件。這是應用正在前臺執行時所處的正常狀態。

  4. Background(後臺狀態)

:應用處在後臺,並且還在執行程式碼。大多數將要進入Suspended狀態的應用,會先短暫進入此狀態。然而,對於請求需要額外的執行時間的應用,會在此狀態保持更長一段時間。另外,如果一個應用要求啟動時直接進入後臺執行,這樣的應用會直接從Not running狀態進入Background狀態,中途不會經過Inactive狀態。比如沒有介面的應用。注此處並不特指沒有介面的應用,其實也可以是有介面的應用,只是如果要直接進入background狀態的話,該應用介面不會被顯示。

  5. Suspended(掛起狀態):應用處在後臺,並且已停止執行程式碼。系統自動的將應用移入此狀態,且在此舉之前不會對應用做任何通知。當處在此狀態時,應用依然駐留記憶體但不執行任何程式程式碼。當系統發生低記憶體告警時,系統將會將處於Suspended狀態的應用清除出記憶體以為正在前臺執行的應用提供足夠的記憶體。

如下圖:



各個程式執行狀態時代理的回撥:
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
      告訴代理程序啟動但還沒進入狀態儲存
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
     告訴代理啟動基本完成程式準備開始執行                             (可以在此方法中加入初始化相關的程式碼

)
- (void)applicationWillResignActive:(UIApplication *)application
    當應用程式將要入非活動狀態執行,在此期間,應用程式不接收訊息或事件,比如來電話了
- (void)applicationDidBecomeActive:(UIApplication *)application 
     當應用程式入活動狀態執行,這個剛好跟上面那個方法相反(當應用從啟動到前臺,或從後臺轉入前臺都會呼叫此方法)
- (void)applicationDidEnterBackground:(UIApplication *)application
    當程式被推送到後臺的時候呼叫。所以要設定後臺繼續執行,則在這個函式裡面設定即可
- (void)applicationWillEnterForeground:(UIApplication *)application
當程式從後臺將要重新回到前臺時候呼叫,這個剛好跟上面的那個方法相反。
- (void)applicationWillTerminate:(UIApplication *)application
當程式將要退出是被呼叫,通常是用來儲存資料和一些退出前的清理工作。這個需要要設定UIApplicationExitsOnSuspend的鍵值。
- (void)applicationDidFinishLaunching:(UIApplication*)application
當程式載入後執行
在上面8個方法對應的方法中鍵入NSLog列印。
現在啟動程式看看執行的順序:
啟動程式
lifeCycle[40428:11303] willFinishLaunchingWithOptions
lifeCycle[40428:11303] didFinishLaunchingWithOptions
lifeCycle[40428:11303] applicationDidBecomeActive
按下home鍵
lifeCycle[40428:11303] applicationWillResignActive
lifeCycle[40428:11303] applicationDidEnterBackground
雙擊home鍵,再開啟程式
lifeCycle[40428:11303] applicationWillEnterForeground
lifeCycle[40428:11303] applicationDidBecomeActive

二、關於main函式,UIApplication類和UIApplication代理類

        每一個iPhone程式都包含一個UIApplication物件,它管理整個程式的生命週期,從載入第一個顯示介面開始,並且監聽系統事件、程式事件排程整個程式的執行。

int main(int argc, char *argv[]) {  
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];  
    int retVal = UIApplicationMain(argc, argv, nil, nil);  
    [pool release];  
    return retVal;  

在main函式中第二行程式碼UI Application Main(argc, argv, nil, nil);對UIApplication物件進行了初始化,這個物件是隱含的,這個方法除了argc 和 argv 引數外,另外這個函式還有兩個字串引數來識別UI Application類和UI Application代理類,在這裡預設是2個nil,第一個引數為nil就預設把UI Application類作為預設值進行初始化,可以在這裡不填nil而是使用自己定義的UI Application子類。至於第二個引數nil,這裡有了UI Application物件怎麼又出來一個UI Application代理類物件呢?這裡需要說明UI Application物件說是管理整個程式的生命週期其實它是什麼具體的事情都不幹,它只負責監聽事件當需要做實際工作的時候就交給UI Application代理類去做,UI Application相當於傳令官負責只把命令傳達給UI Application代理類這個士兵,然後由這個士兵真正去衝鋒陷陣,所以需要給UI Application物件設定代理類。

三、 iOS應用狀態切換:

1. 應用啟動週期

     當應用啟動時,將從Not running狀態進入foreground或者直接進入background執行。進入前臺時,其實最終是要進到Active狀態,中途會先短暫進入到Inactive狀態。在應用啟動時,系統會建立一個process和一個主thread,並且在主thread中呼叫main函式,即上面二提到的。 main函式在建立工程時由Xcode自動生成。main函式負責UIApplication物件初始化,及設定UIApplication代理類等等。在應用初始化並準備進到前臺執行之前的大部分工作都在main函式中完成。

應用被啟動直到前臺執行的過程如下圖,右側部分為呼叫的UIApplication代理類的方法。


如果你的應用要求啟動後直接進入到Backgroundu狀態,則對應的啟動過程和上稍有區別,主要不同是,上面的應用是進入到active,而你的應用要進入到background,並且處理事件,當沒有事件處理時,會被掛起進入到Suspended狀態。如下圖所示。


需要注意的一點是:對於從Not running狀態直接進入到background狀態的應用,在啟動進入到background狀態時,如果應用有介面,系統仍然會載入使用者介面檔案,只是不會顯示在應用的window上面。
    為了在程式中確定你的程式是進入到了foreground還是background,你可以在application:didFinishLaunchingWithOptions:   方法中檢測UIApplication類物件的applicationState屬性,如果應用進入到了foreground,則屬性值為UIApplicationStateInactive,如果進入到了background,則為UIApplicationStateBackground。

檢測示例程式碼:

UIApplicationState state = [UIApplication sharedApplication].applicationState;
    return (state==UIApplicationStateActive || state==UIApplicationStateInactive );

    注:當應用啟動時要求開啟一個URL,則此類應用的啟動過程和三中的兩個圖又有稍微區別, 具體如下:

具有自定義URL模式的應用必須能夠處理所有傳遞給它的URLs。所有的URL都是傳遞給應用的代理來處理,無論當前應用是處在啟動階段或是正在執行running或是在後臺background。為了能夠處理URL請求,你的應用代理必須實現下面的介面方法:

(1)使用application:didFinishingLaunchingWithOptions:方法檢索URL資訊,並且決定是否想要開啟這個URL,這個方法只有在應用被啟動的時候呼叫。

(2)iOS4.2或更新的版本,使用方法application:openURL:sourceApplication:annotation:方法去開啟檔案。

(3)iOS4.1或更老的版本,使用方法application:handleOpenURL:方法去開啟檔案。

當URL請求到達時,如果你的應用沒在正在執行,則會被啟動並且移到前臺執行以開啟URL。你的application:didFinishingLaunchingWithOptions:方法實現中應該包含從選項字典options dictionary中檢索URL並且判斷該應用能否開啟它的部分。如果能夠開啟,則返回YES,讓方法application:openURL:sourceApplication:annotation:或方法application:handleOpenURL:去處理具體的URL開啟過程。對於要求啟動時開啟URL的應用,啟動順序如下圖所示:


當URL請求到來時,如果你的應用正在background執行或被suspended,它將會被移到前臺以開啟URL。之後不久,系統將會呼叫應用代理的application:openURL:sourceApplication:annotation:方法去檢測URL並開啟它。如果你的應用代理沒有實現這個方法(或者當前系統是iOS4.1或更老的版本),系統將會呼叫應用代理的application:handleOpenURL:方法來代替。下面是喚醒後臺或掛起的應用,去開啟URL的程式執行流程,如下圖所示:


支援自定義URL模式的應用,可以在應用啟動和去處理URL之前,這個過程之間指定不同的啟動畫面影象。具體細節,請看Apple官方文件iPhoneAppProgrammingGuide.pdf第85頁,“Providing Launch Images for Custom URL Schemes”。

2. 響應中斷

當一個基於警告的中斷(諸如電話來電)發生時,應用會暫時從active狀態切換到Inactive狀態,以給系統提供機會提示使用者,讓使用者決定如何處理。在使用者決定如何處理此中斷警告之前,應用將一直處於Inactive狀態。 在使用者做出選擇後,當前應用或者回到active狀態繼續執行,或者直接切換到background狀態以讓位於其它的應用執行。此種情況下,應用執行流程如下圖所示:


在iOS5中,notification,特指顯示banner方式的notification,並不會像上面的中斷一樣使當前處於active狀態的應用切換到Inactive狀態。此類通知的banner放置在你的應用視窗的上邊沿之上,所以你的應用依然處在active狀態,並且繼續像以前一樣接收touch events。但是,如果使用者拉下banner去呈現通知中心內容時,當前應用將會和上面基於警告的中斷一樣切換到inactive狀態。此時應用將一直處於Inactive狀態直到使用者對拉下的banner通知做出處理,或許僅僅清除通知或者啟動另外一個應用。相應的當前應用要麼切換回active狀態繼續執行或者切換到background狀態。使用者可以通過Settings應用來配置哪些Notifications以banner的形式顯示,哪些以alert警告的形式顯示。

     使用者按“休眠/喚醒”鍵是另外一種型別的中斷,這類中斷促使應用被deactived,當用戶按下“休眠/喚醒”鍵時,系統除能觸控事件,deactivate當前的應用,並且鎖屏。針對使用資料保護進行加密檔案的應用,鎖屏事件除了上面的deactivated應用,除能觸控事件之外還有其它的處理過程。

當中斷髮生時,會做什麼?

對於基於警告的中斷將會導致使用者暫時對應用失去控制。當前應用繼續在前臺foreground執行,但是不再接收任何觸控事件。(事實上,應用只是不再接收觸控類事件,其它型別的事件比如accelerometer事件,和通知Notification,應用仍然接收。)所以為了響應這些變化,應用需要在applicationWillResignActive:方法中做以下工作:

(1)停止timers及終止其它週期性任務。

(2)停止任何正在執行的元資料查詢。

(3)不再初始化任何新任務。

(4)暫停電影播放(在AirPlay上的播放除外)

(5)遊戲進入暫停狀態。

(6)恢復OpenGL ES幀率。

(7)暫停任何正在臨界區執行的分發佇列或操作佇列。(當然,當應用處於inactive狀態時,應用仍然可以繼續處理網路請求以及其它一些對時間敏感的後臺任務)

        當應用恢復切換回active狀態時,將會在applicationDidBecomeActive:方法中恢復應用被掛起時執行applicationWillResignActive:方法中所做的所有工作。因此,當應用重新被啟用reactivate時,應用應該重啟timers,恢復任何分發佇列,以及恢復OpenGL ES幀率。但是,遊戲不應該自動恢復執行,應該繼續保持在暫停狀態直到使用者手動恢復它們。

        當用戶按下“休眠/喚醒” 鍵時,帶有NSFileProtectionComplete保護選項需要對檔案進行保護的應用必須關閉所有對檔案的引用。對於帶有密碼的裝置,按下“休眠/喚醒”鍵時,鎖屏,並且強制系統扔掉解密金鑰,以使完全保護使能。當屏被鎖時,任何嘗試訪問相應受保護檔案的操作都將fail。所以如果你的應用中有此類受保護的檔案時,你應該在applicationWillResignActive:方法中關閉所有對這些檔案的引用,並且在applicationDidBecomeActive:方法中重新開啟對此類檔案的引用。

在通話過程中,調整你的應用的UI

當用戶正在接電話,並且返回你的應用繼續保持通話,此時狀態列的高度應該增加以反應使用者正在通話的事實。相似的,當用戶結束通話時,狀態列的高度應該縮減恢復常規高度。處理狀態列高度變化的最好方法是使用view controllers去管理你的應用views。當狀態列frame size改變時,view controllers會自動調整它們所管理的所有內部檢視。

如果你的應用因為某些原因而沒有使用view controllers,則你應該手動響應狀態列frame size的變化,具體即通過註冊UIApplicationDidChangeStatusBarFrameNotification通知來實現。通知處理函式handler應該獲取狀態列的高度並且使用這些資料來適度調整當前應用所包含檢視的高度。

3. 切向後臺background狀態

當用戶按下"Home"鍵或者系統啟動另外一個應用時,前臺foreground應用首先切換到Inactive狀態,然後切換到Background狀態。此轉換將會導致先後呼叫應用代理的applicationWillResignActive:applicationDidEnterBackground:方法。在applicationDidEnterBackground:方法返回後,大部分應用在之後不久轉入suspended狀態。對於請求特定後臺background任務的應用,比如播放音樂應用,或者那些請求需要額外執行時間的應用,可能會繼續執行更長一段時間。具體流程如下圖所示:


注:應用從froeground切換到background只有在支援多工並且執行iOS4.0或更新版本系統的裝置上才會發生。所有其它的情況,應用不是切向後臺,而是直接終止,並且從記憶體中清除。

應用切向後臺background時應該做什麼

應用可以在applicationDidEnterBackground:方法中做些切向background狀態前需要做的一些準備工作,當切向background狀態時,所有的應用需要做以下事情:

(1)應用介面快照。當applicationDidEnterBackground:方法返回時,系統儲存應用介面的快照,並且使用快照圖片作為轉換動畫。如果在你的應用介面中有涉及到敏感資訊的檢視,則你應該在applicationDidEnterBackground:方法返回前隱藏或者修改這些檢視。

(2)儲存使用者資料和應用狀態資訊。所有沒有儲存的改變都應該在切向background狀態前寫入磁碟以儲存。這一步是必須的,因為你的應用在後臺時很有可能因為多種其它原因而被很快kill掉。根據需要你可以在background thread後臺執行緒中執行這些操作。

(3)釋放盡可能多的記憶體資源。

applicationDidEnterBackground:方法允許最多有5秒的時間去完成任何任務然後返回。實際中,此方法應該儘可能快的返回。如果在時間到期之後,此方法沒有返回,則應用即被kill掉,並且清除所佔用的記憶體。如果你的應用確實需要更多的時間去執行任務,可以呼叫beginBackgroundTaskWithExpirationHandler:方法請求後臺執行時間,然後啟動一個能長期執行任務的執行緒。無論你是否啟動一個執行後臺任務的執行緒,applicationDidEnterBackground:方法都必須在5秒後退出。

注:UIApplicationDidEnterBackgroundNotification通知也會發送,以讓應用對此通知感興趣的部分知道當前應用正切向background狀態。你的應用中的物件可以使用預設的通知中心註冊這個通知。

依據不同的應用場合,應用切向後臺時還有很多其它的事情需要做,比如active狀態的Bonjour服務應該暫停,應用應該停止呼叫OpenGL ES函式。

因為前臺應用在使用系統資源和硬體時一直比後臺應用具有更高的優先權。執行在後臺的應用應該對此差異有心理準備,並且在後臺執行時要調整它們的訪問資源行為。特別的,當應用切向background時尤其要遵循以下幾點:

(1)不要在應用程式碼中呼叫任何OpenGL ES的東西。當應用在後臺執行時不可以建立EAGLContext物件或者發出任何OpenGL ES繪畫命令,使用這些呼叫將會導致應用立即被kill掉。應用也必須保證先前提交發出的所有命令在應用切向background狀態前都已執行完畢。具體細節請參考“OpenGL ES Programming Guide for iOS”中“Implementing a Multitasking-aware OpenGL ES Application”部分。

(2)在應用掛起suspended之前取消所有Bonjour相關的服務。當應用轉向後臺,並且在被掛起前,應用應該unregister Bonjour服務並且關掉任何和網路服務相關的sockets監聽。掛起的應用是沒法響應這些服務請求的。如果你的應用不關掉這些和Bonjour相關的服務,當應用被掛起的時候,系統會自動幫你關掉這些服務。

(3)在基於網路sockets的應用中,需要處理連線失敗的情況。當你的應用因為某些原因而被掛起時,系統可能會拆除socket連線。只要你的應用對儘可能多的網路錯誤情況都有很好的處理,像丟掉訊號等,此類問題不會導致你的應用出現不正常。當應用從後臺退出恢復執行時,如果遇到sockets使用錯誤,簡單的重建socket連線即可。

(4)在切向background狀態前儲存應用狀態。在低記憶體告警時,後臺應用可能會被清除出記憶體以釋放空間。處於suspended狀態的應用被優先清除記憶體,並且在被清除前不會給出任何通知。因此,當應用切入background狀態前一定要儲存足夠多的應用狀態資訊以便後面恢復時使用。

(5)當切向後臺時,釋放所有不再需要的記憶體。如果你的應用保持著一個很大的記憶體快取物件(比如影象),則切入後臺前,釋放所有的對這些快取物件的引用。

(6)在被掛起前停止使用系統共享資源。使用系統共享資源(比如Address Book或Calendar Data)的應用,在被掛起前必須停止對這些共享資源的使用。對這些資源的使用,前臺應用具有更高的優先使用權,如果發現你的應用在被掛起後還沒有停止對這些共享資源的使用,則應該將被kill掉。

(7)避免更新應用視窗和檢視。當應用處在後臺時,應用視窗和檢視是不可見的,所以不需要更新它他。儘管在後臺建立和操縱視窗和檢視物件並不會導致應用被kill掉,但是可以考慮將這些工作推遲到應用返回前臺時執行。

(8)響應外部附件連線和失去連線通知。針對和外部附件有通訊的應用,當應用切向background狀態時,系統會發送一個disconnection通知。應用必須註冊此通知並且使用它去關掉當前的附件訪問session。當應用返回foreground時,會有一個與之匹配的通知被髮送,給應用提供重新建立session的機會。

(9)切向後臺時,清除行為警告相關的資源。為了在應用相互切換之間儲存應用上下文,當應用切向後臺時,系統並不自動dismiss action sheets(UIActionSheet)和alert views(UIAlertView)。由應用設計者去提供具本的清除方案。對於執行在iOS4.0版本之前的應用,在退出時action sheets和alerts仍然被dismiss掉,以讓應用的取消處理函式有機會去執行。

(10)切向後臺時,移除所有敏感檢視資訊。因為系統會快照應用介面並且生成應用切換動畫,所以帶有敏感資訊的檢視或視窗必須隱藏或移除,具體原因前面已介紹。

(11)應用在後臺執行時執行最少量化的工作。系統給後臺執行的應用的執行時間和給前臺執行的應用相比,通常非常有限。如果應用在後臺播放音訊或者監測位置變化,則應用應該僅關注此任務,所有不必要的任務都應該被推遲。在後臺執行時間過長的應用會被系統throttled back或者直接被kill掉。

當應用因為系統記憶體告警需要被清除出記憶體時,應用會呼叫他的代理的applicationWillTerminate:方法去執行應用退出前的最後的任務。

後臺應用的記憶體使用

當應用切入background時,每個應用應該釋放盡可能多的實際佔用的記憶體。系統儘量嘗試在記憶體中同時保持儘量多的應用,但是當記憶體即將耗盡時,系統會終止那些掛起suspended的應用以回收記憶體。然而那些消耗很大數量的記憶體同時又處於後臺background執行的應用會優先被終止。

實事求是的講,就是當你的應用在不再需要的時候要儘快的移除對那些用過物件的引用。移除引用允許自動引用計數系統去釋放物件並且回收記憶體。然而,如果應用為了改進效能而使用了快取,則應用應該在切換至後臺狀態前等待並且釋放這些快取。下面是一些需要回收的物件的例子:

(1)快取的影象物件

(2)比較大的多媒體檔案或資料檔案,這些檔案可以從磁碟重新裝載。

(3)任何應用當前不再需要的物件,並且這些物件後面又可以很容易重新建立。

為了幫助您的應用程式,減少其記憶體佔用,系統會自動釋放出許多幕後用於支援您的應用程式的物件。例如:

(1)釋放所有的核心動畫層的後備儲存,以避免這些層繼續在螢幕上顯示,同時又不改變當前層的屬性。並且並不釋放層物件自已。

(2)移除所有對快取影象的引用。(如果應用沒有對這些影象強引用,則他們隨後即被移除記憶體)

(3)釋放一些系統管理的其它的資料快取。

4. 返回前臺foreground

如果應用曾被移入後臺,相應的任務被停止,則此時返回前臺時可以重啟任務繼續執行。應用的applicationWillEnterForeground:方法應該恢復所有在applicationDidEnterBackground:方法所做的工作。同時,applicationDidBecomeActive:方法應該繼續執行在應用啟動時所做的同樣的啟用任務的操作。應用從後臺切入前臺的程式流程如下圖所示:


注:如果應用在預設的通知中心註冊了UIApplicationWillEnterForegroudNotification通知,則當應用重新進入前臺時,該通知也是可用的。

(1)在應用切向前臺被喚醒時處理通知佇列

被掛起的應用要時刻準備當恢復foreground或background狀態時去處理所有的通知佇列。因為應用被掛起時不能執行任何程式碼,因此沒有辦法處理那些和諸如方向改變、時間改變、偏好改變、以及其它的影響應用的外觀的行為或狀態等等。為了保證這些改變不丟失,系統將這些相關的通知入佇列,並且當應用恢復foreground或background重新執行程式碼時,立即將這些通知發往應用。為了防止應用恢復時因為通知過多而過載,系統會合並事件並且僅傳遞一個能夠反應自從應用被掛起有網路改變的單個通知。

具體通知合併規則如下表所示:


大部分通知直接傳遞給註冊它作的observers,然而像方向改變這樣的通知很明顯是被系統框架解析的,這樣的通知以另外的方式傳遞給應用。

通知佇列典型的在任何觸控事件和使用者輸入之前被投遞向應用的主執行迴圈main run loop。大多數應用應該能夠足夠快的處理這些事件以致於不會造成應用恢復時有任何明顯的滯後。然而,如果發現你的應用在從後臺恢復時看起來明顯呆滯,則可以使用Instruments去確定是否是通知處理程式碼正在執行而造成了延遲。 一個應用在返回前臺時也會接收所有自從上更新後被標記為dirty的檢視的更新通知。處於後臺background執行的應用也可以呼叫setNeedsDisplay或setNeedsDisplayInRect:方法去請求檢視更新。然而,因為這時介面不可見,所以系統合併這些請求並且只有當應用恢復前臺後才去更新檢視。

(2)從容的處理本地改變

當應用處於掛起suspended狀態時,如果使用者改變了當前語言設定,則當應用返回前臺的時候可以使用NSCurrentLocalDidChaneNotification通知來強制任何包含本地敏感資訊(像日期、時間、數字等等)的檢視進行更新。當然,避免本地資訊相關的事件處理的最好的方法還是以那種更容易更新檢視的方式來寫更新檢視的程式碼。比如:

a.使用autoupdatingCurrentLocal類方法來檢索NSLocal物件。此方法返回一個本地物件,該物件響應本地改變並且自動更新自已。所以,你不需要再去重新建立它。然後,當本地資訊改變時,你的應用仍然需要去重新整理那些包含本地資訊的檢視。

b.無論任何時候本地資訊改變時都去重新建立快取日期或者數字格式物件。

(3)響應應用設定改變

如果應用包含被Settings應用所管理的設定,則應用應該關注NSUserDefaultsDidChangeNotification通知。因為當你的應用處於後臺或被掛起狀態時,使用者可以修改設定,所以你的應用中可以使用這個通知來響應任何重要的設定改變。某些情況下,響應此通知可以幫助關掉一些潛在的安全漏洞。例如,email程式應該響應使用者帳戶資訊的改變,如果不能成功的監測這些改變將會造成一些隱私和安全方面的問題。比如,使用者很有可能傳送郵件時還是使用的是老使用者帳戶,即使那個帳戶已經不再屬於該使用者,然而使用者確絲毫不情以為用的就是新帳戶。當應用接收到該通知時,應用應該重新載入所有和設定相關的東西並且適當的復位使用者介面,如果必要的話。比如密碼或其它的安全相關的資訊改變時,應用應該隱藏任何先前顯示的資訊並且強制使用者輸入新密碼。

5.應用終止

儘管應用通常被切向後臺或被掛起,但是如果有任何下面的情況發生時,應用將被終止並且清除出記憶體:

(1)應用依賴於 iOS4.0以前的版本OS

(2)應用部署在執行iOS4.0版本作業系統的裝置上

(3)當前裝置不支援多工

(4)應用在Info.plist檔案中包含UIApplicationExitOnSuspend key。

如果應用將被終止時正在前臺或後臺執行,系統將會呼叫應用代理的applicationWillTerminate:方法以使應用能做退出前的任何需要的回收處理。你可以使用此方法儲存使用者資料或應用狀態資訊,以供應用隨後重新啟動恢復狀態時使用。該方法最長執行時限為5秒,過期應用即被kill掉並且移除記憶體。

注:應用當前被suspended時,不會呼叫 applicationWillTerminate:方法。

即使是使用iOS SDK4或更新的版本SDK開發應用,也應該考慮應用在沒有任何通知時被kill掉的情況。使用者可以使用多工UI很明確的kill掉某個應用。除此之外,如果發生記憶體告警,系統也會從記憶體中移除應用以釋放空間。處於suspended狀態的應用被終止時不會有任何通知。但是如果應用當前正在後臺background執行,則當應用要被終止時,系統會呼叫應用代理的applicationWillTerminate:方法。應用不可以在此方法中申請額外的後臺執行時間。

6.主執行迴圈main run loop

應用主執行迴圈負責處理所有使用者相關的事件。UIApplication物件在應用啟動時安裝主執行迴圈並且使用此迴圈去處理事件和處理基於檢視的介面更新。正如名字所表明的,該主執行迴圈是在應用的主執行緒app's main thread中執行的。以此保證所有使用者事件是按照它們被接收時的順序序列的執行。

下圖展示了主執行迴圈的結構以及使用者事件如何導致了應用行為。當用戶和應用互動時,和這些互動相關的事件由系統自動產生並且藉助UIKit設定的特殊埠傳遞給應用。事件在應用內部以佇列的形式存在並且一個一個的被分發到應用的主執行迴圈去執行。UIApplication物件是第一個接收事件的物件,並且決定需要如何處理事件。觸控事件通常被分發到應用的主視窗物件,並且最終分發到發生該觸控事件的檢視上面。其它的事件傳遞也許會經過各種各樣的應用物件而與觸控事件傳遞稍微有所不同。


在iOS應用中可以傳遞很多型別的事件。最常見的事件列在下表中:



這些事件型別中的大部分通過應用的主執行迴圈進行傳遞,但是還有一些並不是的。例如:accelerometer事件直接被傳遞到應用指定的accelerometer代理對像。關於系統如何處理大多數型別事件,包括touch、remote control、motion、accelerometer,以及gyroscopic事件,

一些像觸控、遠端控制類的事件,通常被應用的響應物件處理。響應物件存在於應用的任何地方。(UIApplication物件,view物件,view controller物件等等都是響應物件的例子)。大多數事件是以特定的響應物件為目標,但是也可以被傳遞給其它的響應物件(藉助響應鏈),例如:一個不處理任何事件的view可以將事件傳遞給它的父view或傳遞給view controller。

發生在controls類的檢視(例如button)上的事件的處理過程和發生在其它型別的views上的觸控事件處理過程有些不一樣。因為發生在control類的物件上面的互動行為只有非常有限的幾種,因此這些互動重新打包進active message並且傳遞給合適的目標物件。  這種target-action的設計模式,使應用通過control型別的view物件去觸發一段自定義程式碼的執行變得非常容易。