圖片沒有,詳情查看? https://blog.csdn.net/freezing_yu/article/details/16988055
一、iOS應(yīng)用程序狀態(tài)機(jī)一共有五種狀態(tài):
1.Not running:應(yīng)用還沒有啟動(dòng),或者應(yīng)用正在運(yùn)行但是途中被系統(tǒng)停止。
2.Inactive:當(dāng)前應(yīng)用正在前臺(tái)運(yùn)行,但是并不接收事件(當(dāng)前或許正在執(zhí)行其它代碼)。一般每當(dāng)應(yīng)用要從一個(gè)狀態(tài)切換到另一個(gè)不同的狀態(tài)時(shí),中途過渡會(huì)短暫停留在此狀態(tài)。唯一在此狀態(tài)停留時(shí)間比較長(zhǎng)的情況是:當(dāng)用戶鎖屏?xí)r,或者系統(tǒng)提示用戶去響應(yīng)某些(諸如電話來電、有未讀短信等)事件的時(shí)候。
3.Active:當(dāng)前應(yīng)用正在前臺(tái)運(yùn)行,并且接收事件。這是應(yīng)用正在前臺(tái)運(yùn)行時(shí)所處的正常狀態(tài)。
4.Background:應(yīng)用處在后臺(tái),并且還在執(zhí)行代碼。大多數(shù)將要進(jìn)入Suspended狀態(tài)的應(yīng)用,會(huì)先短暫進(jìn)入此狀態(tài)。然而,對(duì)于請(qǐng)求需要額外的執(zhí)行時(shí)間的應(yīng)用,會(huì)在此狀態(tài)保持更長(zhǎng)一段時(shí)間。另外,如果一個(gè)應(yīng)用要求啟動(dòng)時(shí)直接進(jìn)入后臺(tái)運(yùn)行,這樣的應(yīng)用會(huì)直接從Not running狀態(tài)進(jìn)入Background狀態(tài),中途不會(huì)經(jīng)過Inactive狀態(tài)。比如沒有界面的應(yīng)用。注此處并不特指沒有界面的應(yīng)用,其實(shí)也可以是有界面的應(yīng)用,只是如果要直接進(jìn)入background狀態(tài)的話,該應(yīng)用界面不會(huì)被顯示。
5.Suspended:應(yīng)用處在后臺(tái),并且已停止執(zhí)行代碼。系統(tǒng)自動(dòng)的將應(yīng)用移入此狀態(tài),且在此舉之前不會(huì)對(duì)應(yīng)用做任何通知。當(dāng)處在此狀態(tài)時(shí),應(yīng)用依然駐留內(nèi)存但不執(zhí)行任何程序代碼。當(dāng)系統(tǒng)發(fā)生低內(nèi)存告警時(shí),系統(tǒng)將會(huì)將處于Suspended狀態(tài)的應(yīng)用清除出內(nèi)存以為正在前臺(tái)運(yùn)行的應(yīng)用提供足夠的內(nèi)存。
如下圖:
注意:運(yùn)行在iOS3.2或更早期版本操作系統(tǒng)之上的應(yīng)用并不進(jìn)入后background和suspended狀態(tài)。另外,一些即使運(yùn)行在iOS4或更新版本操作系統(tǒng)但是不支持多任務(wù)或后臺(tái)執(zhí)行的應(yīng)用,也不會(huì)進(jìn)入background和suspended狀態(tài)。相應(yīng)的這些應(yīng)用在從前臺(tái)運(yùn)行狀態(tài)離開時(shí)會(huì)直接被終止。
大多時(shí)候狀態(tài)轉(zhuǎn)換通過調(diào)用你的應(yīng)用委托對(duì)象繼承的Delegate方法來完成。開發(fā)人員可以在提供的這些繼承方法中做任何事,以響應(yīng)狀態(tài)轉(zhuǎn)換。相關(guān)繼承的方法及介紹如下所示:
application:didFinishLaunchingWithOptions:這是程序啟動(dòng)時(shí)調(diào)用的函數(shù)??梢栽诖朔椒ㄖ屑尤氤跏蓟嚓P(guān)的代碼。
applicationDidBecomeActive:應(yīng)用在準(zhǔn)備進(jìn)入前臺(tái)運(yùn)行時(shí)執(zhí)行的函數(shù)。(當(dāng)應(yīng)用從啟動(dòng)到前臺(tái),或從后臺(tái)轉(zhuǎn)入前臺(tái)都會(huì)調(diào)用此方法)
applicationWillResignActive:應(yīng)用當(dāng)前正要從前臺(tái)運(yùn)行狀態(tài)離開時(shí)執(zhí)行的函數(shù)。
applicationDidEnterBackground: 此時(shí)應(yīng)用處在background狀態(tài),并且沒有執(zhí)行任何代碼,未來將被掛起進(jìn)入suspended狀態(tài)。
applicationWillEnterForeground:當(dāng)前應(yīng)用正從后臺(tái)移入前臺(tái)運(yùn)行狀態(tài),但是當(dāng)前還沒有到Active狀態(tài)時(shí)執(zhí)行的函數(shù)。
applicationWillTerminate:當(dāng)前應(yīng)用即將被終止,在終止前調(diào)用的函數(shù)。如果應(yīng)用當(dāng)前處在suspended,此方法不會(huì)被調(diào)用。
二、關(guān)于main函數(shù),UIApplication類和UIApplication代理類
每一個(gè)iPhone程序都包含一個(gè)UIApplication對(duì)象,它管理整個(gè)程序的生命周期,從加載第一個(gè)顯示界面開始,并且監(jiān)聽系統(tǒng)事件、程序事件調(diào)度整個(gè)程序的執(zhí)行。
int main(int argc, char *argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;
}
在main函數(shù)中第二行代碼UI Application Main(argc, argv, nil, nil);對(duì)UIApplication對(duì)象進(jìn)行了初始化,這個(gè)對(duì)象是隱含的,這個(gè)方法除了argc 和 argv 參數(shù)外,另外這個(gè)函數(shù)還有兩個(gè)字符串參數(shù)來識(shí)別UI Application類和UI Application代理類,在這里默認(rèn)是2個(gè)nil,第一個(gè)參數(shù)為nil就默認(rèn)把UI Application類作為缺省值進(jìn)行初始化,可以在這里不填nil而是使用自己定義的UI Application子類。至于第二個(gè)參數(shù)nil,這里有了UI Application對(duì)象怎么又出來一個(gè)UI Application代理類對(duì)象呢?這里需要說明UI Application對(duì)象說是管理整個(gè)程序的生命周期其實(shí)它是什么具體的事情都不干,它只負(fù)責(zé)監(jiān)聽事件當(dāng)需要做實(shí)際工作的時(shí)候就交給UI Application代理類去做,UI Application相當(dāng)于傳令官負(fù)責(zé)只把命令傳達(dá)給UI Application代理類這個(gè)士兵,然后由這個(gè)士兵真正去沖鋒陷陣,所以需要給UI Application對(duì)象設(shè)置代理類。
三、 iOS應(yīng)用狀態(tài)切換:
1. 應(yīng)用啟動(dòng)周期
當(dāng)應(yīng)用啟動(dòng)時(shí),將從Not running狀態(tài)進(jìn)入foreground或者直接進(jìn)入background運(yùn)行。進(jìn)入前臺(tái)時(shí),其實(shí)最終是要進(jìn)到Active狀態(tài),中途會(huì)先短暫進(jìn)入到Inactive狀態(tài)。在應(yīng)用啟動(dòng)時(shí),系統(tǒng)會(huì)創(chuàng)建一個(gè)process和一個(gè)主thread,并且在主thread中調(diào)用main函數(shù),即上面二提到的。 main函數(shù)在創(chuàng)建工程時(shí)由Xcode自動(dòng)生成。main函數(shù)負(fù)責(zé)UIApplication對(duì)象初始化,及設(shè)置UIApplication代理類等等。在應(yīng)用初始化并準(zhǔn)備進(jìn)到前臺(tái)運(yùn)行之前的大部分工作都在main函數(shù)中完成。
應(yīng)用被啟動(dòng)直到前臺(tái)運(yùn)行的過程如下圖,右側(cè)部分為調(diào)用的UIApplication代理類的方法。
如果你的應(yīng)用要求啟動(dòng)后直接進(jìn)入到Backgroundu狀態(tài),則對(duì)應(yīng)的啟動(dòng)過程和上稍有區(qū)別,主要不同是,上面的應(yīng)用是進(jìn)入到active,而你的應(yīng)用要進(jìn)入到background,并且處理事件,當(dāng)沒有事件處理時(shí),會(huì)被掛起進(jìn)入到Suspended狀態(tài)。如下圖所示。
需要注意的一點(diǎn)是:對(duì)于從Not running狀態(tài)直接進(jìn)入到background狀態(tài)的應(yīng)用,在啟動(dòng)進(jìn)入到background狀態(tài)時(shí),如果應(yīng)用有界面,系統(tǒng)仍然會(huì)加載用戶界面文件,只是不會(huì)顯示在應(yīng)用的window上面。
為了在程序中確定你的程序是進(jìn)入到了foreground還是background,你可以在application:didFinishLaunchingWithOptions:方法中檢測(cè)UIApplication類對(duì)象的applicationState屬性,如果應(yīng)用進(jìn)入到了foreground,則屬性值為UIApplicationStateInactive,如果進(jìn)入到了background,則為UIApplicationStateBackground。
檢測(cè)示例代碼:
UIApplicationState state = [UIApplication sharedApplication].applicationState;
return (state==UIApplicationStateActive|| state==UIApplicationStateInactive );
注:當(dāng)應(yīng)用啟動(dòng)時(shí)要求打開一個(gè)URL,則此類應(yīng)用的啟動(dòng)過程和三中的兩個(gè)圖又有稍微區(qū)別, 具體如下:
具有自定義URL模式的應(yīng)用必須能夠處理所有傳遞給它的URLs。所有的URL都是傳遞給應(yīng)用的代理來處理,無論當(dāng)前應(yīng)用是處在啟動(dòng)階段或是正在運(yùn)行running或是在后臺(tái)background。為了能夠處理URL請(qǐng)求,你的應(yīng)用代理必須實(shí)現(xiàn)下面的接口方法:
(1)使用application:didFinishingLaunchingWithOptions:方法檢索URL信息,并且決定是否想要打開這個(gè)URL,這個(gè)方法只有在應(yīng)用被啟動(dòng)的時(shí)候調(diào)用。
(2)iOS4.2或更新的版本,使用方法application:openURL:sourceApplication:annotation:方法去打開文件。
(3)iOS4.1或更老的版本,使用方法application:handleOpenURL:方法去打開文件。
當(dāng)URL請(qǐng)求到達(dá)時(shí),如果你的應(yīng)用沒在正在運(yùn)行,則會(huì)被啟動(dòng)并且移到前臺(tái)運(yùn)行以打開URL。你的application:didFinishingLaunchingWithOptions:方法實(shí)現(xiàn)中應(yīng)該包含從選項(xiàng)字典options dictionary中檢索URL并且判斷該應(yīng)用能否打開它的部分。如果能夠打開,則返回YES,讓方法application:openURL:sourceApplication:annotation:或方法application:handleOpenURL:去處理具體的URL打開過程。對(duì)于要求啟動(dòng)時(shí)打開URL的應(yīng)用,啟動(dòng)順序如下圖所示:
當(dāng)URL請(qǐng)求到來時(shí),如果你的應(yīng)用正在background運(yùn)行或被suspended,它將會(huì)被移到前臺(tái)以打開URL。之后不久,系統(tǒng)將會(huì)調(diào)用應(yīng)用代理的application:openURL:sourceApplication:annotation:方法去檢測(cè)URL并打開它。如果你的應(yīng)用代理沒有實(shí)現(xiàn)這個(gè)方法(或者當(dāng)前系統(tǒng)是iOS4.1或更老的版本),系統(tǒng)將會(huì)調(diào)用應(yīng)用代理的application:handleOpenURL:方法來代替。下面是喚醒后臺(tái)或掛起的應(yīng)用,去打開URL的程序執(zhí)行流程,如下圖所示:
支持自定義URL模式的應(yīng)用,可以在應(yīng)用啟動(dòng)和去處理URL之前,這個(gè)過程之間指定不同的啟動(dòng)畫面圖像。具體細(xì)節(jié),請(qǐng)看Apple官方文檔iPhoneAppProgrammingGuide.pdf第85頁(yè),“Providing Launch Images for Custom URL Schemes”。
2. 響應(yīng)中斷
當(dāng)一個(gè)基于警告的中斷(諸如電話來電)發(fā)生時(shí),應(yīng)用會(huì)暫時(shí)從active狀態(tài)切換到Inactive狀態(tài),以給系統(tǒng)提供機(jī)會(huì)提示用戶,讓用戶決定如何處理。在用戶決定如何處理此中斷警告之前,應(yīng)用將一直處于Inactive狀態(tài)。 在用戶做出選擇后,當(dāng)前應(yīng)用或者回到active狀態(tài)繼續(xù)運(yùn)行,或者直接切換到background狀態(tài)以讓位于其它的應(yīng)用運(yùn)行。此種情況下,應(yīng)用執(zhí)行流程如下圖所示:
在iOS5中,notification,特指顯示banner方式的notification,并不會(huì)像上面的中斷一樣使當(dāng)前處于active狀態(tài)的應(yīng)用切換到Inactive狀態(tài)。此類通知的banner放置在你的應(yīng)用窗口的上邊沿之上,所以你的應(yīng)用依然處在active狀態(tài),并且繼續(xù)像以前一樣接收touch events。但是,如果用戶拉下banner去呈現(xiàn)通知中心內(nèi)容時(shí),當(dāng)前應(yīng)用將會(huì)和上面基于警告的中斷一樣切換到inactive狀態(tài)。此時(shí)應(yīng)用將一直處于Inactive狀態(tài)直到用戶對(duì)拉下的banner通知做出處理,或許僅僅清除通知或者啟動(dòng)另外一個(gè)應(yīng)用。相應(yīng)的當(dāng)前應(yīng)用要么切換回active狀態(tài)繼續(xù)運(yùn)行或者切換到background狀態(tài)。用戶可以通過Settings應(yīng)用來配置哪些Notifications以banner的形式顯示,哪些以alert警告的形式顯示。
用戶按“休眠/喚醒”鍵是另外一種類型的中斷,這類中斷促使應(yīng)用被deactived,當(dāng)用戶按下“休眠/喚醒”鍵時(shí),系統(tǒng)除能觸摸事件,deactivate當(dāng)前的應(yīng)用,并且鎖屏。針對(duì)使用數(shù)據(jù)保護(hù)進(jìn)行加密文件的應(yīng)用,鎖屏事件除了上面的deactivated應(yīng)用,除能觸控事件之外還有其它的處理過程。
當(dāng)中斷發(fā)生時(shí),會(huì)做什么?
對(duì)于基于警告的中斷將會(huì)導(dǎo)致用戶暫時(shí)對(duì)應(yīng)用失去控制。當(dāng)前應(yīng)用繼續(xù)在前臺(tái)foreground運(yùn)行,但是不再接收任何觸控事件。(事實(shí)上,應(yīng)用只是不再接收觸控類事件,其它類型的事件比如accelerometer事件,和通知Notification,應(yīng)用仍然接收。)所以為了響應(yīng)這些變化,應(yīng)用需要在applicationWillResignActive:方法中做以下工作:
(1)停止timers及終止其它周期性任務(wù)。
(2)停止任何正在運(yùn)行的元數(shù)據(jù)查詢。
(3)不再初始化任何新任務(wù)。
(4)暫停電影播放(在AirPlay上的播放除外)
(5)游戲進(jìn)入暫停狀態(tài)。
(6)恢復(fù)OpenGL ES幀率。
(7)暫停任何正在臨界區(qū)執(zhí)行的分發(fā)隊(duì)列或操作隊(duì)列。(當(dāng)然,當(dāng)應(yīng)用處于inactive狀態(tài)時(shí),應(yīng)用仍然可以繼續(xù)處理網(wǎng)絡(luò)請(qǐng)求以及其它一些對(duì)時(shí)間敏感的后臺(tái)任務(wù))
當(dāng)應(yīng)用恢復(fù)切換回active狀態(tài)時(shí),將會(huì)在applicationDidBecomeActive:方法中恢復(fù)應(yīng)用被掛起時(shí)執(zhí)行applicationWillResignActive:方法中所做的所有工作。因此,當(dāng)應(yīng)用重新被激活reactivate時(shí),應(yīng)用應(yīng)該重啟timers,恢復(fù)任何分發(fā)隊(duì)列,以及恢復(fù)OpenGL ES幀率。但是,游戲不應(yīng)該自動(dòng)恢復(fù)運(yùn)行,應(yīng)該繼續(xù)保持在暫停狀態(tài)直到用戶手動(dòng)恢復(fù)它們。
當(dāng)用戶按下“休眠/喚醒” 鍵時(shí),帶有NSFileProtectionComplete保護(hù)選項(xiàng)需要對(duì)文件進(jìn)行保護(hù)的應(yīng)用必須關(guān)閉所有對(duì)文件的引用。對(duì)于帶有密碼的設(shè)備,按下“休眠/喚醒”鍵時(shí),鎖屏,并且強(qiáng)制系統(tǒng)扔掉解密密鑰,以使完全保護(hù)使能。當(dāng)屏被鎖時(shí),任何嘗試訪問相應(yīng)受保護(hù)文件的操作都將fail。所以如果你的應(yīng)用中有此類受保護(hù)的文件時(shí),你應(yīng)該在applicationWillResignActive:方法中關(guān)閉所有對(duì)這些文件的引用,并且在applicationDidBecomeActive:方法中重新打開對(duì)此類文件的引用。
在通話過程中,調(diào)整你的應(yīng)用的UI:
當(dāng)用戶正在接電話,并且返回你的應(yīng)用繼續(xù)保持通話,此時(shí)狀態(tài)欄的高度應(yīng)該增加以反應(yīng)用戶正在通話的事實(shí)。相似的,當(dāng)用戶結(jié)束通話時(shí),狀態(tài)欄的高度應(yīng)該縮減恢復(fù)常規(guī)高度。處理狀態(tài)欄高度變化的最好方法是使用view controllers去管理你的應(yīng)用views。當(dāng)狀態(tài)欄frame size改變時(shí),view controllers會(huì)自動(dòng)調(diào)整它們所管理的所有內(nèi)部視圖。
如果你的應(yīng)用因?yàn)槟承┰蚨鴽]有使用view controllers,則你應(yīng)該手動(dòng)響應(yīng)狀態(tài)欄frame size的變化,具體即通過注冊(cè)UIApplicationDidChangeStatusBarFrameNotification通知來實(shí)現(xiàn)。通知處理函數(shù)handler應(yīng)該獲取狀態(tài)欄的高度并且使用這些數(shù)據(jù)來適度調(diào)整當(dāng)前應(yīng)用所包含視圖的高度。
3. 切向后臺(tái)background狀態(tài)
當(dāng)用戶按下"Home"鍵或者系統(tǒng)啟動(dòng)另外一個(gè)應(yīng)用時(shí),前臺(tái)foreground應(yīng)用首先切換到Inactive狀態(tài),然后切換到Background狀態(tài)。此轉(zhuǎn)換將會(huì)導(dǎo)致先后調(diào)用應(yīng)用代理的applicationWillResignActive:和applicationDidEnterBackground:方法。在applicationDidEnterBackground:方法返回后,大部分應(yīng)用在之后不久轉(zhuǎn)入suspended狀態(tài)。對(duì)于請(qǐng)求特定后臺(tái)background任務(wù)的應(yīng)用,比如播放音樂應(yīng)用,或者那些請(qǐng)求需要額外執(zhí)行時(shí)間的應(yīng)用,可能會(huì)繼續(xù)執(zhí)行更長(zhǎng)一段時(shí)間。具體流程如下圖所示:
注:應(yīng)用從froeground切換到background只有在支持多任務(wù)并且運(yùn)行iOS4.0或更新版本系統(tǒng)的設(shè)備上才會(huì)發(fā)生。所有其它的情況,應(yīng)用不是切向后臺(tái),而是直接終止,并且從內(nèi)存中清除。
應(yīng)用切向后臺(tái)background時(shí)應(yīng)該做什么:
應(yīng)用可以在applicationDidEnterBackground:方法中做些切向background狀態(tài)前需要做的一些準(zhǔn)備工作,當(dāng)切向background狀態(tài)時(shí),所有的應(yīng)用需要做以下事情:
(1)應(yīng)用界面快照。當(dāng)applicationDidEnterBackground:方法返回時(shí),系統(tǒng)保存應(yīng)用界面的快照,并且使用快照?qǐng)D片作為轉(zhuǎn)換動(dòng)畫。如果在你的應(yīng)用界面中有涉及到敏感信息的視圖,則你應(yīng)該在applicationDidEnterBackground:方法返回前隱藏或者修改這些視圖。
(2)保存用戶數(shù)據(jù)和應(yīng)用狀態(tài)信息。所有沒有保存的改變都應(yīng)該在切向background狀態(tài)前寫入磁盤以保存。這一步是必須的,因?yàn)槟愕膽?yīng)用在后臺(tái)時(shí)很有可能因?yàn)槎喾N其它原因而被很快kill掉。根據(jù)需要你可以在background thread后臺(tái)線程中執(zhí)行這些操作。
(3)釋放盡可能多的內(nèi)存資源。
applicationDidEnterBackground:方法允許最多有5秒的時(shí)間去完成任何任務(wù)然后返回。實(shí)際中,此方法應(yīng)該盡可能快的返回。如果在時(shí)間到期之后,此方法沒有返回,則應(yīng)用即被kill掉,并且清除所占用的內(nèi)存。如果你的應(yīng)用確實(shí)需要更多的時(shí)間去執(zhí)行任務(wù),可以調(diào)用beginBackgroundTaskWithExpirationHandler:方法請(qǐng)求后臺(tái)執(zhí)行時(shí)間,然后啟動(dòng)一個(gè)能長(zhǎng)期執(zhí)行任務(wù)的線程。無論你是否啟動(dòng)一個(gè)執(zhí)行后臺(tái)任務(wù)的線程,applicationDidEnterBackground:方法都必須在5秒后退出。
注:UIApplicationDidEnterBackgroundNotification通知也會(huì)發(fā)送,以讓應(yīng)用對(duì)此通知感興趣的部分知道當(dāng)前應(yīng)用正切向background狀態(tài)。你的應(yīng)用中的對(duì)象可以使用默認(rèn)的通知中心注冊(cè)這個(gè)通知。
依據(jù)不同的應(yīng)用場(chǎng)合,應(yīng)用切向后臺(tái)時(shí)還有很多其它的事情需要做,比如active狀態(tài)的Bonjour服務(wù)應(yīng)該暫停,應(yīng)用應(yīng)該停止調(diào)用OpenGL ES函數(shù)。
因?yàn)榍芭_(tái)應(yīng)用在使用系統(tǒng)資源和硬件時(shí)一直比后臺(tái)應(yīng)用具有更高的優(yōu)先權(quán)。運(yùn)行在后臺(tái)的應(yīng)用應(yīng)該對(duì)此差異有心理準(zhǔn)備,并且在后臺(tái)運(yùn)行時(shí)要調(diào)整它們的訪問資源行為。特別的,當(dāng)應(yīng)用切向background時(shí)尤其要遵循以下幾點(diǎn):
(1)不要在應(yīng)用代碼中調(diào)用任何OpenGL ES的東西。當(dāng)應(yīng)用在后臺(tái)運(yùn)行時(shí)不可以創(chuàng)建EAGLContext對(duì)象或者發(fā)出任何OpenGL ES繪畫命令,使用這些調(diào)用將會(huì)導(dǎo)致應(yīng)用立即被kill掉。應(yīng)用也必須保證先前提交發(fā)出的所有命令在應(yīng)用切向background狀態(tài)前都已執(zhí)行完畢。具體細(xì)節(jié)請(qǐng)參考“OpenGL ES Programming Guide for iOS”中“Implementing a Multitasking-aware OpenGL ES Application”部分。
(2)在應(yīng)用掛起suspended之前取消所有Bonjour相關(guān)的服務(wù)。當(dāng)應(yīng)用轉(zhuǎn)向后臺(tái),并且在被掛起前,應(yīng)用應(yīng)該unregister Bonjour服務(wù)并且關(guān)掉任何和網(wǎng)絡(luò)服務(wù)相關(guān)的sockets監(jiān)聽。掛起的應(yīng)用是沒法響應(yīng)這些服務(wù)請(qǐng)求的。如果你的應(yīng)用不關(guān)掉這些和Bonjour相關(guān)的服務(wù),當(dāng)應(yīng)用被掛起的時(shí)候,系統(tǒng)會(huì)自動(dòng)幫你關(guān)掉這些服務(wù)。
(3)在基于網(wǎng)絡(luò)sockets的應(yīng)用中,需要處理連接失敗的情況。當(dāng)你的應(yīng)用因?yàn)槟承┰蚨粧炱饡r(shí),系統(tǒng)可能會(huì)拆除socket連接。只要你的應(yīng)用對(duì)盡可能多的網(wǎng)絡(luò)錯(cuò)誤情況都有很好的處理,像丟掉信號(hào)等,此類問題不會(huì)導(dǎo)致你的應(yīng)用出現(xiàn)不正常。當(dāng)應(yīng)用從后臺(tái)退出恢復(fù)執(zhí)行時(shí),如果遇到sockets使用錯(cuò)誤,簡(jiǎn)單的重建socket連接即可。
(4)在切向background狀態(tài)前保存應(yīng)用狀態(tài)。在低內(nèi)存告警時(shí),后臺(tái)應(yīng)用可能會(huì)被清除出內(nèi)存以釋放空間。處于suspended狀態(tài)的應(yīng)用被優(yōu)先清除內(nèi)存,并且在被清除前不會(huì)給出任何通知。因此,當(dāng)應(yīng)用切入background狀態(tài)前一定要保存足夠多的應(yīng)用狀態(tài)信息以便后面恢復(fù)時(shí)使用。
(5)當(dāng)切向后臺(tái)時(shí),釋放所有不再需要的內(nèi)存。如果你的應(yīng)用保持著一個(gè)很大的內(nèi)存緩存對(duì)象(比如圖像),則切入后臺(tái)前,釋放所有的對(duì)這些緩存對(duì)象的引用。
(6)在被掛起前停止使用系統(tǒng)共享資源。使用系統(tǒng)共享資源(比如Address Book或Calendar Data)的應(yīng)用,在被掛起前必須停止對(duì)這些共享資源的使用。對(duì)這些資源的使用,前臺(tái)應(yīng)用具有更高的優(yōu)先使用權(quán),如果發(fā)現(xiàn)你的應(yīng)用在被掛起后還沒有停止對(duì)這些共享資源的使用,則應(yīng)該將被kill掉。
(7)避免更新應(yīng)用窗口和視圖。當(dāng)應(yīng)用處在后臺(tái)時(shí),應(yīng)用窗口和視圖是不可見的,所以不需要更新它他。盡管在后臺(tái)創(chuàng)建和操縱窗口和視圖對(duì)象并不會(huì)導(dǎo)致應(yīng)用被kill掉,但是可以考慮將這些工作推遲到應(yīng)用返回前臺(tái)時(shí)執(zhí)行。
(8)響應(yīng)外部附件連接和失去連接通知。針對(duì)和外部附件有通信的應(yīng)用,當(dāng)應(yīng)用切向background狀態(tài)時(shí),系統(tǒng)會(huì)發(fā)送一個(gè)disconnection通知。應(yīng)用必須注冊(cè)此通知并且使用它去關(guān)掉當(dāng)前的附件訪問session。當(dāng)應(yīng)用返回foreground時(shí),會(huì)有一個(gè)與之匹配的通知被發(fā)送,給應(yīng)用提供重新建立session的機(jī)會(huì)。
(9)切向后臺(tái)時(shí),清除行為警告相關(guān)的資源。為了在應(yīng)用相互切換之間保存應(yīng)用上下文,當(dāng)應(yīng)用切向后臺(tái)時(shí),系統(tǒng)并不自動(dòng)dismiss action sheets(UIActionSheet)和alert views(UIAlertView)。由應(yīng)用設(shè)計(jì)者去提供具本的清除方案。對(duì)于運(yùn)行在iOS4.0版本之前的應(yīng)用,在退出時(shí)action sheets和alerts仍然被dismiss掉,以讓應(yīng)用的取消處理函數(shù)有機(jī)會(huì)去運(yùn)行。
(10)切向后臺(tái)時(shí),移除所有敏感視圖信息。因?yàn)橄到y(tǒng)會(huì)快照應(yīng)用界面并且生成應(yīng)用切換動(dòng)畫,所以帶有敏感信息的視圖或窗口必須隱藏或移除,具體原因前面已介紹。
(11)應(yīng)用在后臺(tái)運(yùn)行時(shí)執(zhí)行最少量化的工作。系統(tǒng)給后臺(tái)運(yùn)行的應(yīng)用的執(zhí)行時(shí)間和給前臺(tái)運(yùn)行的應(yīng)用相比,通常非常有限。如果應(yīng)用在后臺(tái)播放音頻或者監(jiān)測(cè)位置變化,則應(yīng)用應(yīng)該僅關(guān)注此任務(wù),所有不必要的任務(wù)都應(yīng)該被推遲。在后臺(tái)執(zhí)行時(shí)間過長(zhǎng)的應(yīng)用會(huì)被系統(tǒng)throttled back或者直接被kill掉。
當(dāng)應(yīng)用因?yàn)橄到y(tǒng)內(nèi)存告警需要被清除出內(nèi)存時(shí),應(yīng)用會(huì)調(diào)用他的代理的applicationWillTerminate:方法去執(zhí)行應(yīng)用退出前的最后的任務(wù)。
后臺(tái)應(yīng)用的內(nèi)存使用:
當(dāng)應(yīng)用切入background時(shí),每個(gè)應(yīng)用應(yīng)該釋放盡可能多的實(shí)際占用的內(nèi)存。系統(tǒng)盡量嘗試在內(nèi)存中同時(shí)保持盡量多的應(yīng)用,但是當(dāng)內(nèi)存即將耗盡時(shí),系統(tǒng)會(huì)終止那些掛起suspended的應(yīng)用以回收內(nèi)存。然而那些消耗很大數(shù)量的內(nèi)存同時(shí)又處于后臺(tái)background運(yùn)行的應(yīng)用會(huì)優(yōu)先被終止。
實(shí)事求是的講,就是當(dāng)你的應(yīng)用在不再需要的時(shí)候要盡快的移除對(duì)那些用過對(duì)象的引用。移除引用允許自動(dòng)引用計(jì)數(shù)系統(tǒng)去釋放對(duì)象并且回收內(nèi)存。然而,如果應(yīng)用為了改進(jìn)性能而使用了緩存,則應(yīng)用應(yīng)該在切換至后臺(tái)狀態(tài)前等待并且釋放這些緩存。下面是一些需要回收的對(duì)象的例子:
(1)緩存的圖像對(duì)象
(2)比較大的多媒體文件或數(shù)據(jù)文件,這些文件可以從磁盤重新裝載。
(3)任何應(yīng)用當(dāng)前不再需要的對(duì)象,并且這些對(duì)象后面又可以很容易重新創(chuàng)建。
為了幫助您的應(yīng)用程序,減少其內(nèi)存占用,系統(tǒng)會(huì)自動(dòng)釋放出許多幕后用于支持您的應(yīng)用程序的對(duì)象。例如:
(1)釋放所有的核心動(dòng)畫層的后備存儲(chǔ),以避免這些層繼續(xù)在屏幕上顯示,同時(shí)又不改變當(dāng)前層的屬性。并且并不釋放層對(duì)象自已。
(2)移除所有對(duì)緩存圖像的引用。(如果應(yīng)用沒有對(duì)這些圖像強(qiáng)引用,則他們隨后即被移除內(nèi)存)
(3)釋放一些系統(tǒng)管理的其它的數(shù)據(jù)緩存。
4. 返回前臺(tái)foreground
如果應(yīng)用曾被移入后臺(tái),相應(yīng)的任務(wù)被停止,則此時(shí)返回前臺(tái)時(shí)可以重啟任務(wù)繼續(xù)執(zhí)行。應(yīng)用的applicationWillEnterForeground:方法應(yīng)該恢復(fù)所有在applicationDidEnterBackground:方法所做的工作。同時(shí),applicationDidBecomeActive:方法應(yīng)該繼續(xù)執(zhí)行在應(yīng)用啟動(dòng)時(shí)所做的同樣的激活任務(wù)的操作。應(yīng)用從后臺(tái)切入前臺(tái)的程序流程如下圖所示:
注:如果應(yīng)用在默認(rèn)的通知中心注冊(cè)了UIApplicationWillEnterForegroudNotification通知,則當(dāng)應(yīng)用重新進(jìn)入前臺(tái)時(shí),該通知也是可用的。
(1)在應(yīng)用切向前臺(tái)被喚醒時(shí)處理通知隊(duì)列
被掛起的應(yīng)用要時(shí)刻準(zhǔn)備當(dāng)恢復(fù)foreground或background狀態(tài)時(shí)去處理所有的通知隊(duì)列。因?yàn)閼?yīng)用被掛起時(shí)不能執(zhí)行任何代碼,因此沒有辦法處理那些和諸如方向改變、時(shí)間改變、偏好改變、以及其它的影響應(yīng)用的外觀的行為或狀態(tài)等等。為了保證這些改變不丟失,系統(tǒng)將這些相關(guān)的通知入隊(duì)列,并且當(dāng)應(yīng)用恢復(fù)foreground或background重新執(zhí)行代碼時(shí),立即將這些通知發(fā)往應(yīng)用。為了防止應(yīng)用恢復(fù)時(shí)因?yàn)橥ㄖ^多而過載,系統(tǒng)會(huì)合并事件并且僅傳遞一個(gè)能夠反應(yīng)自從應(yīng)用被掛起有網(wǎng)絡(luò)改變的單個(gè)通知。
具體通知合并規(guī)則如下表所示:
大部分通知直接傳遞給注冊(cè)它作的observers,然而像方向改變這樣的通知很明顯是被系統(tǒng)框架解析的,這樣的通知以另外的方式傳遞給應(yīng)用。
通知隊(duì)列典型的在任何觸控事件和用戶輸入之前被投遞向應(yīng)用的主運(yùn)行循環(huán)main run loop。大多數(shù)應(yīng)用應(yīng)該能夠足夠快的處理這些事件以致于不會(huì)造成應(yīng)用恢復(fù)時(shí)有任何明顯的滯后。然而,如果發(fā)現(xiàn)你的應(yīng)用在從后臺(tái)恢復(fù)時(shí)看起來明顯呆滯,則可以使用Instruments去確定是否是通知處理代碼正在運(yùn)行而造成了延遲。
一個(gè)應(yīng)用在返回前臺(tái)時(shí)也會(huì)接收所有自從上更新后被標(biāo)記為dirty的視圖的更新通知。處于后臺(tái)background運(yùn)行的應(yīng)用也可以調(diào)用setNeedsDisplay或setNeedsDisplayInRect:方法去請(qǐng)求視圖更新。然而,因?yàn)檫@時(shí)界面不可見,所以系統(tǒng)合并這些請(qǐng)求并且只有當(dāng)應(yīng)用恢復(fù)前臺(tái)后才去更新視圖。
(2)從容的處理本地改變
當(dāng)應(yīng)用處于掛起suspended狀態(tài)時(shí),如果用戶改變了當(dāng)前語言設(shè)置,則當(dāng)應(yīng)用返回前臺(tái)的時(shí)候可以使用NSCurrentLocalDidChaneNotification通知來強(qiáng)制任何包含本地敏感信息(像日期、時(shí)間、數(shù)字等等)的視圖進(jìn)行更新。當(dāng)然,避免本地信息相關(guān)的事件處理的最好的方法還是以那種更容易更新視圖的方式來寫更新視圖的代碼。比如:
a.使用autoupdatingCurrentLocal類方法來檢索NSLocal對(duì)象。此方法返回一個(gè)本地對(duì)象,該對(duì)象響應(yīng)本地改變并且自動(dòng)更新自已。所以,你不需要再去重新創(chuàng)建它。然后,當(dāng)本地信息改變時(shí),你的應(yīng)用仍然需要去刷新那些包含本地信息的視圖。
b.無論任何時(shí)候本地信息改變時(shí)都去重新創(chuàng)建緩存日期或者數(shù)字格式對(duì)象。
(3)響應(yīng)應(yīng)用設(shè)置改變
如果應(yīng)用包含被Settings應(yīng)用所管理的設(shè)置,則應(yīng)用應(yīng)該關(guān)注NSUserDefaultsDidChangeNotification通知。因?yàn)楫?dāng)你的應(yīng)用處于后臺(tái)或被掛起狀態(tài)時(shí),用戶可以修改設(shè)置,所以你的應(yīng)用中可以使用這個(gè)通知來響應(yīng)任何重要的設(shè)置改變。某些情況下,響應(yīng)此通知可以幫助關(guān)掉一些潛在的安全漏洞。例如,email程序應(yīng)該響應(yīng)用戶帳戶信息的改變,如果不能成功的監(jiān)測(cè)這些改變將會(huì)造成一些隱私和安全方面的問題。比如,用戶很有可能發(fā)送郵件時(shí)還是使用的是老用戶帳戶,即使那個(gè)帳戶已經(jīng)不再屬于該用戶,然而用戶確絲毫不情以為用的就是新帳戶。當(dāng)應(yīng)用接收到該通知時(shí),應(yīng)用應(yīng)該重新加載所有和設(shè)置相關(guān)的東西并且適當(dāng)?shù)膹?fù)位用戶接口,如果必要的話。比如密碼或其它的安全相關(guān)的信息改變時(shí),應(yīng)用應(yīng)該隱藏任何先前顯示的信息并且強(qiáng)制用戶輸入新密碼。
5.應(yīng)用終止
盡管應(yīng)用通常被切向后臺(tái)或被掛起,但是如果有任何下面的情況發(fā)生時(shí),應(yīng)用將被終止并且清除出內(nèi)存:
(1)應(yīng)用依賴于 iOS4.0以前的版本OS
(2)應(yīng)用部署在運(yùn)行iOS4.0版本操作系統(tǒng)的設(shè)備上
(3)當(dāng)前設(shè)備不支持多任務(wù)
(4)應(yīng)用在Info.plist文件中包含UIApplicationExitOnSuspend key。
如果應(yīng)用將被終止時(shí)正在前臺(tái)或后臺(tái)運(yùn)行,系統(tǒng)將會(huì)調(diào)用應(yīng)用代理的applicationWillTerminate:方法以使應(yīng)用能做退出前的任何需要的回收處理。你可以使用此方法保存用戶數(shù)據(jù)或應(yīng)用狀態(tài)信息,以供應(yīng)用隨后重新啟動(dòng)恢復(fù)狀態(tài)時(shí)使用。該方法最長(zhǎng)運(yùn)行時(shí)限為5秒,過期應(yīng)用即被kill掉并且移除內(nèi)存。
注:應(yīng)用當(dāng)前被suspended時(shí),不會(huì)調(diào)用 applicationWillTerminate:方法。
即使是使用iOS SDK4或更新的版本SDK開發(fā)應(yīng)用,也應(yīng)該考慮應(yīng)用在沒有任何通知時(shí)被kill掉的情況。用戶可以使用多任務(wù)UI很明確的kill掉某個(gè)應(yīng)用。除此之外,如果發(fā)生內(nèi)存告警,系統(tǒng)也會(huì)從內(nèi)存中移除應(yīng)用以釋放空間。處于suspended狀態(tài)的應(yīng)用被終止時(shí)不會(huì)有任何通知。但是如果應(yīng)用當(dāng)前正在后臺(tái)background運(yùn)行,則當(dāng)應(yīng)用要被終止時(shí),系統(tǒng)會(huì)調(diào)用應(yīng)用代理的applicationWillTerminate:方法。應(yīng)用不可以在此方法中申請(qǐng)額外的后臺(tái)執(zhí)行時(shí)間。
6.主運(yùn)行循環(huán)main run loop
應(yīng)用主運(yùn)行循環(huán)負(fù)責(zé)處理所有用戶相關(guān)的事件。UIApplication對(duì)象在應(yīng)用啟動(dòng)時(shí)安裝主運(yùn)行循環(huán)并且使用此循環(huán)去處理事件和處理基于視圖的界面更新。正如名字所表明的,該主運(yùn)行循環(huán)是在應(yīng)用的主線程app's main thread中運(yùn)行的。以此保證所有用戶事件是按照它們被接收時(shí)的順序串行的執(zhí)行。
下圖展示了主運(yùn)行循環(huán)的結(jié)構(gòu)以及用戶事件如何導(dǎo)致了應(yīng)用行為。當(dāng)用戶和應(yīng)用交互時(shí),和這些交互相關(guān)的事件由系統(tǒng)自動(dòng)產(chǎn)生并且借助UIKit設(shè)定的特殊端口傳遞給應(yīng)用。事件在應(yīng)用內(nèi)部以隊(duì)列的形式存在并且一個(gè)一個(gè)的被分發(fā)到應(yīng)用的主運(yùn)行循環(huán)去執(zhí)行。UIApplication對(duì)象是第一個(gè)接收事件的對(duì)象,并且決定需要如何處理事件。觸控事件通常被分發(fā)到應(yīng)用的主窗口對(duì)象,并且最終分發(fā)到發(fā)生該觸控事件的視圖上面。其它的事件傳遞也許會(huì)經(jīng)過各種各樣的應(yīng)用對(duì)象而與觸控事件傳遞稍微有所不同。
在iOS應(yīng)用中可以傳遞很多類型的事件。最常見的事件列在下表中:
這些事件類型中的大部分通過應(yīng)用的主運(yùn)行循環(huán)進(jìn)行傳遞,但是還有一些并不是的。例如:accelerometer事件直接被傳遞到應(yīng)用指定的accelerometer代理對(duì)像。關(guān)于系統(tǒng)如何處理大多數(shù)類型事件,包括touch、remote control、motion、accelerometer,以及gyroscopic事件,詳見Event Handling Guide for iOS.
一些像觸控、遠(yuǎn)程控制類的事件,通常被應(yīng)用的響應(yīng)對(duì)象處理。響應(yīng)對(duì)象存在于應(yīng)用的任何地方。(UIApplication對(duì)象,view對(duì)象,view controller對(duì)象等等都是響應(yīng)對(duì)象的例子)。大多數(shù)事件是以特定的響應(yīng)對(duì)象為目標(biāo),但是也可以被傳遞給其它的響應(yīng)對(duì)象(借助響應(yīng)鏈),例如:一個(gè)不處理任何事件的view可以將事件傳遞給它的父view或傳遞給view controller。
發(fā)生在controls類的視圖(例如button)上的事件的處理過程和發(fā)生在其它類型的views上的觸控事件處理過程有些不一樣。因?yàn)榘l(fā)生在control類的對(duì)象上面的交互行為只有非常有限的幾種,因此這些交互重新打包進(jìn)active message并且傳遞給合適的目標(biāo)對(duì)象。這種target-action的設(shè)計(jì)模式,使應(yīng)用通過control類型的view對(duì)象去觸發(fā)一段自定義代碼的執(zhí)行變得非常容易。
文章轉(zhuǎn)自:https://blog.csdn.net/freezing_yu/article/details/16988055