標籤:
SDK並沒有提供終止應用程式的方法。要想終止應用程式,蘋果推薦的唯一的方式是按下Home按鈕。
但是Foundation架構中整合了Darwin架構,從而我們可以使用C函數exit(0)來終止Application。當然這隻是對於企業開發人員而言。對於個人開發人員,你這樣做的唯一結果就是,你的應用將會被蘋果商店拒絕。
UIApplication的openUrl方法則是退出應用程式的另一種方法。當你在代碼中調用OpenURL方法時,你的App進程會被終止(掛起),另一個App則被喚醒。
當然兩種退出App的機制和最終效果並不相同。當你使用exit(0)退出程式時,你的App並不僅僅是退出前台,程式所佔用的記憶體也被清除了——這是不可恢複的。如果再次Launch這個App,iOS將重新從磁碟中讀取二進位——這是一份全新的App映像。
openURL則不同,它僅僅是把你的程式掛起,這是可恢複的——你的App僅僅是從前台退出,但後台中仍然存在著。使用者可以在某個時候“喚醒”它,於是你的App又回來了,此時應用程式的狀態仍然喚醒之前的狀態。當然,萬一你運氣不好,iOS也會將你的App徹底從記憶體中回收,一如exit(0)所做的一樣——這一般是系統記憶體緊張的時候。
這兩種方法在某些時候可能需要並存。例如,我們想在App退出之前,喚醒另一個App,比如Safari。同時我們希望自己的App是真正的“退出”,回收App的所有記憶體。
這是一個“悖論”。因為無論exit(0)還是openURL,一旦執行之後,作業系統就會終止進程的執行。只要執行二者中的任何一句語句,另外一個語句就無法執行——因為進程已經終止了。
但在某種情況下,通過對iOS多任務機制的巧妙利用,這個悖論卻是真實成立的。
例如,我們可以利用如下O-C代碼來實現這個目的:
[self performSelector:@selector(exitApp)withObject:nil afterDelay:0.5];
[[UIApplication sharedApplication]openURL:
[NSURLURLWithString:@"appScheme://"]];
exitApp方法實際上就是一句代碼exit(0)。
這樣二者就實現並存了。
首先,我們讓exit(0)延遲0.5秒再執行,而在此之前openURL當然早就執行完了。
performSelector:afterDelay方法將會調度一個任務在某個時間後執行。當然,這個時間不能太長,因為iOS允許app在進入後台之後仍然有一段“存活”時間,但是這個時間不能太長,這樣即算後面的openURL方法執行後,App仍然處於存活狀態,也就有機會去執行所調度任務(即exit(0))。
這段代碼在iOS 5以後都工作得很好。但不幸的是,Swift語言來了。
在Swift中,performSelector方法不再存在。
當然,我們立即想到了另一個替代方案,即GCD:
var dispatchTime: dispatch_time_t =dispatch_time(
DISPATCH_TIME_NOW,Int64(0.5 * Double(NSEC_PER_SEC)))
dispatch_after(dispatchTime,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0),
{
exit(0)
})
UIApplication.sharedApplication().openURL(NSURL(string:"appScheme://")!)
然而,這段代碼根本不能工作。原因未知,很能是一個新的Bug,但我至今沒有看到有人向蘋果Radar過這個問題。
經過一番探索,我發現了讓上述代碼工作的方法,那就是將上述程式碼封裝裹在新的GCD非同步塊中:
dispatch_async(dispatch_get_main_queue(),{()->Voidin
var dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW,Int64(0.5 * Double(NSEC_PER_SEC)))
dispatch_after(dispatchTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0), {
exit(0)
})
UIApplication.sharedApplication().openURL(NSURL(string:"appScheme://")!)
})
如何在OpenUrl之後真正退出App?