https://www.jianshu.com/p/56ae5ca5e867
https://www.imooc.com/wenda/detail/595838
項目中碰到一個需求,就是在退出控制器后進行埋點操作,正常情況我們在controller的delloc中執行埋點的網絡請求就OK了,但是還有一種情況,如果用戶殺死程序,是不會走delloc方法的。這時候需要監聽殺死程序的通知,這里貼下最終代碼,想看思路的請往后看。
- (void)viewDidLoad { [super viewDidLoad]; //監聽通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) name:@"UIApplicationWillTerminateNotification" object:nil]; } //程序被殺死 - (void)applicationWillTerminate:(UIApplication *)application { //進行埋點操作 [self uploadData]; [NSThread sleepForTimeInterval:5]; NSLog(@"程序被殺死"); }
- 一開始想着直接在監聽到殺死App后直接埋點,所以在控制器中加入了如下代碼:
- (void)viewDidLoad { [super viewDidLoad]; //監聽通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) name:@"UIApplicationWillTerminateNotification" object:nil]; } //程序被殺死 - (void)applicationWillTerminate:(UIApplication *)application { //進行埋點操作 [self uploadData]; NSLog(@"程序被殺死"); }
- 本以為這樣就大功告成了,誰知道埋點沒生效,打斷點發現殺死程序后網絡請求並沒有走完。了解到系統執行完回調applicationWillTerminate:后,在那一次主線程 runloop 結束, 系統就會殺死應用進程, 所以后續的網絡請求,磁盤操作,異步代碼 等等就都沒執行了。在網上查找資料主要有兩種方法:1.說要把這里的網絡請求改成在主線程。2.另外一種方法是阻塞主線程,這里貼下該作者的代碼地址https://www.jianshu.com/p/5142ebe74c6d。
- 看了這兩種方法,覺得第一種方法網絡請求改主線程太過麻煩,因為我這里的埋點有好幾個,所以選擇第二種方法,但覺得作者的做法也太麻煩了,按照思路,無非就是阻塞主線程,讓埋點的網絡請求走完才讓主線程結束,這時候我突然靈機一動:我們啟動APP進入歡迎界面一般就需要沉睡幾秒才進入主界面:
[NSThread sleepForTimeInterval:3];
是否可以利用這個方法實現我們的需求?於是我在監聽到App被殺死,進行埋點操作后加入上面的代碼。
- (void)viewDidLoad { [super viewDidLoad]; //監聽通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) name:@"UIApplicationWillTerminateNotification" object:nil]; } //程序被殺死 - (void)applicationWillTerminate:(UIApplication *)application { //進行埋點操作 [self uploadData]; [NSThread sleepForTimeInterval:5]; NSLog(@"程序被殺死"); }
發現此方法確實可行,而且簡單,但有個缺點就是如果網絡請求慢的話,有可能埋點會失敗。大家可以嘗試用NSTimer阻塞,然后埋點網絡請求完后invalidate。
作者:原味丿丿咖啡Vitas
鏈接:https://www.jianshu.com/p/56ae5ca5e867
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
applicationWillTerminate什么時候調用,什么時候不調用
嗨,我已經閱讀了關於applicationWillTerminate被調用和未被調用的幾個問題。
我想總結一下我的理解,因為有幾篇文章講的不同。
對於IOS(無多任務),總是在按下主頁按鈕時調用它。
對於iOS 4及更高版本
一種。按下主屏幕按鈕時不會調用它(因為應用程序移至后台)
b。當從多任務擴展塢中關閉應用程序時調用該方法,並且如果該應用程序在info.plist中禁用了突然終止標志,則不會調用它。(我設置了“應用程序應獲取App Died事件”,即使在從多任務擴展塢中關閉應用程序時,也沒有調用終止函數)
基於此,我有幾個問題
設置應用程序應獲取“ App Died”事件標志是一種好習慣嗎?(我設置了“應用程序應獲取App Died事件”,即使在從多任務擴展塢中關閉應用程序時,也沒有調用終止函數)
要么
與“ info.plist”設置相比,注冊“ UIApplicationWillTerminateNotification”更好嗎?
基本上,我只需要在應用終止時才需要做一些工作,而不必在它移到后台時才需要做。
要么
編輯(1):應用終止后,以下內容將發送到該應用。我怎么抓到它?
程序收到信號:“ SIGKILL”。
編輯(2):
請注意:從多任務擴展塢中卸下時,它在IOS 4及更高版本中不會被調用。您可能以為是。但就我而言,事實並非如此。
我問是否有人知道為什么?還有其他我想念的東西嗎?
另請注意,我設置了“應用程序應獲取應用程序死亡事件”,即使這樣它也沒有被調用。
有人面臨與我類似的問題嗎?
3 回答
簡而言之,除非您UIApplicationExitsOnSuspend在Info.plist中將其設置為YES ,否則在iOS4及更高版本中,無法保證applicationWillTerminate:會被調用。
如文檔所述:
對於支持后台執行的應用程序,當用戶退出應用程序時通常不會調用此方法,因為在這種情況下,應用程序只是移至后台。然而,這種方法可以在其中應用程序在背景中(未暫停)運行情況被調用,該系統需要終止它由於某種原因
(強調我的。)
如果您需要在應用退出之前執行某些操作,則需要在中執行操作applicationDidEnterBackground:。無法捕捉SIGKILL。
據我所知,您的應用程序將在3種情況下死亡。
-
在最終用戶終止后,您可以在中做某事
-[UIApplication applicationWillEnterBackground:],在這種情況下,-[UIApplication applicationWillTerminate:]將不會調用。 -
被系統丟棄,例如內存不足,您可以在中做某事
-[UIApplication applicationWillTerminate:],在這種情況下,我們不知道是否applicationWillEnterBackground:已被調用; -
崩潰了,只能使用某種崩潰報告工具來完成。(編輯:捕捉
SIGKILL是不可能的)

