iOS應用程序狀態切換相關

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

1. Not running:應用還沒有啓動,或者應用正在運行但是途中被系統停止。

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

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

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

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

如下圖:


注意:運行在iOS3.2或更早期版本操作系統之上的應用並不進入後background和suspended狀態。另外,一些即使運行在iOS4或更新版本操作系統但是不支持多任務或後臺執行的應用,也不會進入background和suspended狀態。相應的這些應用在從前臺運行狀態離開時會直接被終止。

大多時候狀態轉換通過調用你的應用委託對象繼承的Delegate方法來完成。開發人員可以在提供的這些繼承方法中做任何事,以響應狀態轉換。相關繼承的方法及介紹如下所示:

application:didFinishLaunchingWithOptions:   這是程序啓動時調用的函數。可以在此方法中加入初始化相關的代碼。

applicationDidBecomeActive:  應用在準備進入前臺運行時執行的函數。(當應用從啓動到前臺,或從後臺轉入前臺都會調用此方法

applicationWillResignActive:   應用當前正要從前臺運行狀態離開時執行的函數。

applicationDidEnterBackground: 此時應用處在background狀態,並且沒有執行任何代碼,未來將被掛起進入suspended狀態。

applicationWillEnterForeground:  當前應用正從後臺移入前臺運行狀態,但是當前還沒有到Active狀態時執行的函數。

applicationWillTerminate:  當前應用即將被終止,在終止前調用的函數。如果應用當前處在suspended,此方法不會被調用。


二、關於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事件,詳見Event Handling Guide for iOS.

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

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

 

轉載地址:http://blog.csdn.net/duanyipeng/article/details/7101829

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章