來自 CocoaChina,加一些自己的認(rèn)識(shí)边败。
1慈缔、應(yīng)用程序的狀態(tài)
- Not running未運(yùn)行:程序沒啟動(dòng)叮称。
- Inactive未激活:程序在前臺(tái)運(yùn)行,不過沒有接收到事件藐鹤。在沒有事件處理情況下程序通常停留在這個(gè)狀態(tài)瓤檐。
- Active激活:程序在前臺(tái)運(yùn)行而且接收到了事件。這也是前臺(tái)的一個(gè)正常的模式娱节。
- Backgroud后臺(tái):程序在后臺(tái)而且能執(zhí)行代碼挠蛉,大多數(shù)程序進(jìn)入這個(gè)狀態(tài)后會(huì)在在這個(gè)狀態(tài)上停留一會(huì)。時(shí)間到之后會(huì)進(jìn)入掛起狀態(tài)(Suspended)肄满。有的程序經(jīng)過特殊的請(qǐng)求后可以長期處于Backgroud狀態(tài)谴古。
- Suspended掛起:程序在后臺(tái)不能執(zhí)行代碼。系統(tǒng)會(huì)自動(dòng)把程序變成這個(gè)狀態(tài)而且不會(huì)發(fā)出通知稠歉。當(dāng)掛起時(shí)掰担,程序還是停留在內(nèi)存中的,當(dāng)系統(tǒng)內(nèi)存低時(shí)怒炸,系統(tǒng)就把掛起的程序清除掉带饱,為前臺(tái)程序提供更多的內(nèi)存。
2阅羹、各個(gè)程序運(yùn)行狀態(tài)時(shí)代理的回調(diào)
①告訴代理進(jìn)程啟動(dòng)但還沒進(jìn)入狀態(tài)保存
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(@"①告訴代理進(jìn)程啟動(dòng)但還沒進(jìn)入狀態(tài)保存");
return YES;
}
②告訴代理啟動(dòng)基本完成程序準(zhǔn)備開始運(yùn)行
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
NSLog(@"②告訴代理啟動(dòng)基本完成程序準(zhǔn)備開始運(yùn)行");
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
其中 launchOptions 是帶有啟動(dòng)參數(shù)的字典纠炮,存儲(chǔ)有此程序啟動(dòng)的原因月趟。launchOptions 中的鍵值對(duì)可以看 UIApplication Class Reference 中的 Launch Options Keys 一節(jié)。
若用戶直接啟動(dòng)恢口,launchOptions 內(nèi)無數(shù)據(jù);
若由其他應(yīng)用程序通過 openURL: 啟動(dòng)孝宗,則 UIApplicationLaunchOptionsURLKey 對(duì)應(yīng)的對(duì)象為啟動(dòng) URL(NSURL),UIApplicationLaunchOptionsSourceApplicationKey 對(duì)應(yīng)啟動(dòng)的源應(yīng)用程序的bundle ID (NSString)耕肩;
若由本地通知啟動(dòng)因妇,則 UIApplicationLaunchOptionsLocalNotificationKey 對(duì)應(yīng)的是為啟動(dòng)應(yīng)用程序的的本地通知對(duì)象(UILocalNotification);
若由遠(yuǎn)程通知啟動(dòng)猿诸,則 UIApplicationLaunchOptionsRemoteNotificationKey 對(duì)應(yīng)的是啟動(dòng)應(yīng)用程序的的遠(yuǎn)程通知信息 userInfo(NSDictionary)婚被;
其他key還有 UIApplicationLaunchOptionsAnnotationKey、UIApplicationLaunchOptionsLocationKey梳虽、
UIApplicationLaunchOptionsNewsstandDownloadsKey址芯。
如果要在啟動(dòng)時(shí),做出一些區(qū)分窜觉,那就需要在下面的代碼做處理谷炸。
比如應(yīng)用可以被某個(gè)其它應(yīng)用調(diào)起,那可能要在啟動(dòng)代碼的地方做出一些驗(yàn)證禀挫,比如以下例子旬陡。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSURL *url = [options objectForKey:UIApplicationLaunchOptionsURLKey];
if (url) {
// do something.
}
NSString *bundleId = [options objectForKey:UIApplicationLaunchOptionsSourceApplicationKey];
if (bundleId) {
// do something.
}
UILocalNotification * localNotify = [options objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotify) {
// do something.
}
NSDictionary * userInfo = [options objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (userInfo) {
// do something.
}
}
③當(dāng)應(yīng)用程序?qū)⒁敕腔顒?dòng)狀態(tài)執(zhí)行,在此期間语婴,應(yīng)用程序不接收消息或事件描孟,比如來電話
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
NSLog(@"③當(dāng)應(yīng)用程序?qū)⒁敕腔顒?dòng)狀態(tài)執(zhí)行,在此期間砰左,應(yīng)用程序不接收消息或事件匿醒,比如來電話");
}
④當(dāng)應(yīng)用程序進(jìn)入活動(dòng)狀態(tài)執(zhí)行
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
NSLog(@"④當(dāng)應(yīng)用程序進(jìn)入活動(dòng)狀態(tài)執(zhí)行");
}
⑤當(dāng)程序被推送到后臺(tái)的時(shí)候調(diào)用。所以要設(shè)置后臺(tái)繼續(xù)運(yùn)行缠导,則在這個(gè)函數(shù)里面設(shè)置即可
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
NSLog(@"⑤當(dāng)程序被推送到后臺(tái)的時(shí)候調(diào)用");
[application beginBackgroundTaskWithExpirationHandler:^{
NSLog(@"begin Background Task With Expiration Handler");
}];
}
⑥當(dāng)程序從后臺(tái)將要重新回到前臺(tái)時(shí)候調(diào)用
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
NSLog(@"⑥當(dāng)程序從后臺(tái)將要重新回到前臺(tái)時(shí)候調(diào)用");
}
⑦當(dāng)程序?qū)⒁顺鍪潜徽{(diào)用廉羔,通常是用來保存數(shù)據(jù)和一些退出前的清理工作。這個(gè)需要要設(shè)置UIApplicationExitsOnSuspend的鍵值
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
NSLog(@"⑦當(dāng)程序?qū)⒁顺鍪潜徽{(diào)用");
}
⑧當(dāng)程序載入后執(zhí)行
- (void)applicationDidFinishLaunching:(UIApplication *)application {
NSLog(@"⑧當(dāng)程序載入后執(zhí)行");
}
程序啟動(dòng)時(shí):
2014-07-01 15:55:14.706 LifeCycle[5845:60b] ①告訴代理進(jìn)程啟動(dòng)但還沒進(jìn)入狀態(tài)保存
2014-07-01 15:55:14.708 LifeCycle[5845:60b] ②告訴代理啟動(dòng)基本完成程序準(zhǔn)備開始運(yùn)行
2014-07-01 15:55:14.709 LifeCycle[5845:60b] ④當(dāng)應(yīng)用程序進(jìn)入活動(dòng)狀態(tài)執(zhí)行
按下Home鍵返回主界面:
2014-07-01 15:56:11.756 LifeCycle[5845:60b] ③當(dāng)應(yīng)用程序?qū)⒁敕腔顒?dòng)狀態(tài)執(zhí)行
2014-07-01 15:56:11.814 LifeCycle[5845:60b] ⑤當(dāng)程序被推送到后臺(tái)的時(shí)候調(diào)用
再次打開程序:
2014-07-01 15:57:19.200 LifeCycle[5845:60b] ⑥當(dāng)程序從后臺(tái)將要重新回到前臺(tái)時(shí)候調(diào)用
2014-07-01 15:57:19.201 LifeCycle[5845:60b] ④當(dāng)應(yīng)用程序進(jìn)入活動(dòng)狀態(tài)執(zhí)行
3酬核、加載應(yīng)用程序進(jìn)入前臺(tái)
4蜜另、加載應(yīng)用程序進(jìn)入后臺(tái)
5、基于警告式響應(yīng)中斷
當(dāng)出現(xiàn)這種中斷時(shí)嫡意,我們需要在- (void)applicationWillResignActive:(UIApplication *)application方法中進(jìn)行如下操作:
①停止timer 和其他周期性的任務(wù)
②停止任何正在運(yùn)行的請(qǐng)求
③暫停視頻的播放
④如果是游戲那就暫停它
⑤減少OpenGL ES的幀率
⑥掛起任何分發(fā)的隊(duì)列和不重要的操作隊(duì)列(你可以繼續(xù)處理網(wǎng)絡(luò)請(qǐng)求或其他時(shí)間敏感的后臺(tái)任務(wù))
當(dāng)程序回到active狀態(tài)举瑰,我們需要在- (void)applicationDidBecomeActive:(UIApplication *)application方法中重新開始上述任務(wù)。不過游戲要回到暫停狀態(tài)蔬螟,不能自動(dòng)開始此迅。
6、進(jìn)入后臺(tái)運(yùn)行
當(dāng)應(yīng)用程序進(jìn)入后臺(tái)時(shí),我們應(yīng)該做些什么耸序?
保存用戶數(shù)據(jù)或狀態(tài)信息忍些,所有沒寫到磁盤的文件或信息,在進(jìn)入后臺(tái)時(shí)坎怪,最后都寫到磁盤去罢坝,因?yàn)槌绦蚩赡茉诤笈_(tái)被殺死。
釋放盡可能釋放的內(nèi)存搅窿。
- (void)applicationDidEnterBackground:(UIApplication *)application
方法有大概5秒的時(shí)間讓你完成這些任務(wù)嘁酿。如果超過時(shí)間還有未完成的任務(wù),你的程序就會(huì)被終止而且從內(nèi)存中清除男应。
如果還需要長時(shí)間的運(yùn)行任務(wù)闹司,可以在該方法中調(diào)用
[application beginBackgroundTaskWithExpirationHandler:^{
NSLog(@"begin Background Task With Expiration Handler");
}];
應(yīng)用程序在后臺(tái)時(shí)的內(nèi)存使用:請(qǐng)求后臺(tái)運(yùn)行時(shí)間和啟動(dòng)線程來運(yùn)行長時(shí)間運(yùn)行的任務(wù)。
在后臺(tái)時(shí)沐飘,每個(gè)應(yīng)用程序都應(yīng)該釋放最大的內(nèi)存游桩。系統(tǒng)努力的保持更多的應(yīng)用程序在后臺(tái)同時(shí) 運(yùn)行。不過當(dāng)內(nèi)存不足時(shí)耐朴,會(huì)終止一些掛起的程序來回收內(nèi)存借卧,那些內(nèi)存最大的程序首先被終止。
事實(shí)上隔箍,應(yīng)用程序應(yīng)該的對(duì)象如果不再使用了谓娃,那就應(yīng)該盡快的去掉強(qiáng)引用脚乡,這樣編譯器可以回收這些內(nèi)存蜒滩。如果你想緩存一些對(duì)象提升程序的性能,你可以在進(jìn)入后臺(tái)時(shí)奶稠,把這些對(duì)象去掉強(qiáng)引用俯艰。
下面這樣的對(duì)象應(yīng)該盡快的去掉強(qiáng)引用:
①圖片對(duì)象
②你可以重新加載的 大的視頻或數(shù)據(jù)文件
③任何沒用而且可以輕易創(chuàng)建的對(duì)象
在后臺(tái)時(shí),為了減少程序占用的內(nèi)存锌订,系統(tǒng)會(huì)自動(dòng)在回收一些系統(tǒng)幫助你開辟的內(nèi)存竹握。比如:
①系統(tǒng)回收Core Animation的后備存儲(chǔ)。
②去掉任何系統(tǒng)引用的緩存圖片
③去掉系統(tǒng)管理數(shù)據(jù)緩存強(qiáng)引用
7辆飘、返回前臺(tái)運(yùn)行
在暫停狀態(tài)的應(yīng)用程序必須準(zhǔn)備處理任何排隊(duì)的通知時(shí)啦辐,它返回到前臺(tái)或后臺(tái)執(zhí)行狀態(tài)。暫停的應(yīng)用程序不執(zhí)行任何代碼蜈项,因此不能處理與方向的變化芹关,時(shí)間的變化,偏好的變化紧卒,以及許多其他會(huì)影響應(yīng)用程序的外觀或狀態(tài)的通知侥衬。為了確保這些更改不會(huì)丟失,系統(tǒng)排隊(duì)許多相關(guān)的通知,并把它們傳遞給應(yīng)用程序轴总,只要它開始再次執(zhí)行代碼(無論是在前景或背景)直颅。為了防止由偏快轉(zhuǎn)為超載與它恢復(fù)時(shí)通知您的應(yīng)用程序,該系統(tǒng)凝聚事件怀樟,并提供一個(gè)單一的通知(每個(gè)相關(guān)類型)功偿,反映了凈變化,因?yàn)槟愕膽?yīng)用程序被暫停往堡。
8脖含、程序終止
程序只要符合以下情況之一,只要進(jìn)入后臺(tái)或掛起狀態(tài)就會(huì)終止:
①iOS4.0以前的系統(tǒng)
②app是基于iOS4.0之前系統(tǒng)開發(fā)的投蝉。
③設(shè)備不支持多任務(wù)
④在Info.plist文件中养葵,程序包含了 UIApplicationExitsOnSuspend 鍵。
app如果終止了瘩缆,系統(tǒng)會(huì)調(diào)用app的代理的方法 - (void)applicationWillTerminate:(UIApplication *)application关拒,這樣可以讓你可以做一些清理工作。你可以保存一些數(shù)據(jù)或app的狀態(tài)庸娱。這個(gè)方法也有5秒鐘的限制着绊。超時(shí)后方法會(huì)返回程序從內(nèi)存中清除。
注意:用戶可以手工關(guān)閉應(yīng)用程序熟尉。
9归露、The Main Run Loop 主運(yùn)行循環(huán)
Main Run Loop負(fù)責(zé)處理用戶相關(guān)的事件。UIApplication對(duì)象在程序啟動(dòng)時(shí)啟動(dòng)main run Loop斤儿,它處理事件和更新視圖的界面剧包。看Main Run Loop就知道往果,它是運(yùn)行在程序的主線程上的疆液。這樣保證了接收到用戶相關(guān)操作的事件是按順序處理的。
用戶操作設(shè)備陕贮,相關(guān)的操作事件被系統(tǒng)生成并通過UIKit的指定端口分發(fā)堕油。事件在內(nèi)部排成隊(duì)列,一個(gè)個(gè)的分發(fā)到Main run loop 去做處理肮之。UIApplication對(duì)象是第一個(gè)接收到時(shí)間的對(duì)象掉缺,它決定事件如何被處理。觸摸事件分發(fā)到主窗口戈擒,窗口再分發(fā)到對(duì)應(yīng)出發(fā)觸摸事件的View眶明。其他的事件通過其他途徑分發(fā)給其他對(duì)象變量做處理。
大部分的事件可以在你的應(yīng)用里分發(fā)峦甩,類似于觸摸事件赘来,遠(yuǎn)程操控事件(線控耳機(jī)等)都是由app的 responder objects 對(duì)象處理的现喳。Responder objects 在你的app里到處都是,比如:UIApplication 對(duì)象犬辰,view對(duì)象嗦篱,view controller 對(duì)象,都是resopnder objects幌缝。大部分事件的目標(biāo)都指定了resopnder object灸促,不過事件也可以傳遞給其他對(duì)象。比如涵卵,如果view對(duì)象不處理事件浴栽,可以傳給父類view或者view controller。