日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

RunLoop总结:RunLoop的应用场景(五)

發布時間:2025/7/25 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 RunLoop总结:RunLoop的应用场景(五) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

今天要介紹的RunLoop應用場景感覺很酷炫,我們可能不常用到,但是對于做Crash 收集的 SDK可能會用得比較頻繁吧。相比關于RunLoop 可以讓應用起死回生,大家都聽說過,可是怎么實現呢?今天我就來實際試驗一下。

資料

  • sunnyxx線下分享RunLoop (這是一份關于線下分享與討論RunLoop的視頻,備用地址:https://pan.baidu.com/s/1pLm4Vf9)
  • 漫談iOS Crash收集框架(簡單介紹了下iOS 中Crash 的一些知識。)
  • IOS程序異常crash捕獲與攔截 (我下面的Demo 就是在這部分代碼上做了簡化,以方便理解)

原理

iOS應用崩潰,常見的崩潰信息有EXC_BAD_ACCESS、SIGABRT XXXXXXX,而這里分為兩種情況,一種是未被捕獲的異常,我們只需要添加一個回調函數,并在應用啟動時調用一個 API即可;另一種是直接發送的 SIGABRT XXXXXXX,這里我們也需要監聽各種信號,然后添加回調函數。

針對情況一,其實我們都見過。我們在收集App崩潰信息時,需要添加一個函數 NSSetUncaughtExceptionHandler(&HandleException),參數 是一個回調函數,在回調函數里獲取到異常的原因,當前的堆棧信息等保存到 dump文件,然后供下次打開App時上傳到服務器。

其實,我們在HandleException回調函數中,可以獲取到當前的RunLoop,然后獲取該RunLoop中的所有Mode,手動運行一遍。

針對情況二,首先針對多種要捕獲的信號,設置好回調函數,然后也是在回調函數中獲取RunLoop,然后拿到所有的Mode,手動運行一遍。

代碼實現

第一步,我創建了一個處理類,并添加一個單例方法。(代碼見末尾的Demo)

第二步,在單例中對象實例化時,添加 異常捕獲 和 signal 處理的 回調函數。

- (void)setCatchExceptionHandler {// 1.捕獲一些異常導致的崩潰NSSetUncaughtExceptionHandler(&HandleException);// 2.捕獲非異常情況,通過signal傳遞出來的崩潰signal(SIGABRT, SignalHandler);signal(SIGILL, SignalHandler);signal(SIGSEGV, SignalHandler);signal(SIGFPE, SignalHandler);signal(SIGBUS, SignalHandler);signal(SIGPIPE, SignalHandler); }

第三步,分別實現 異常捕獲的回調 和 signal 的回調。

void HandleException(NSException *exception) {// 獲取異常的堆棧信息NSArray *callStack = [exception callStackSymbols];NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];[userInfo setObject:callStack forKey:kCaughtExceptionStackInfoKey];CrashHandler *crashObject = [CrashHandler sharedInstance];NSException *customException = [NSException exceptionWithName:[exception name] reason:[exception reason] userInfo:userInfo];[crashObject performSelectorOnMainThread:@selector(handleException:) withObject:customException waitUntilDone:YES]; }void SignalHandler(int signal) {// 這種情況的崩潰信息,就另某他法來捕獲吧NSArray *callStack = [CrashHandler backtrace];NSLog(@"信號捕獲崩潰,堆棧信息:%@",callStack);CrashHandler *crashObject = [CrashHandler sharedInstance];NSException *customException = [NSException exceptionWithName:kSignalExceptionNamereason:[NSString stringWithFormat:NSLocalizedString(@"Signal %d was raised.", nil),signal]userInfo:@{kSignalKey:[NSNumber numberWithInt:signal]}];[crashObject performSelectorOnMainThread:@selector(handleException:) withObject:customException waitUntilDone:YES]; }

第四步,添加讓應用起死回生的 RunLoop 代碼

- (void)handleException:(NSException *)exception {NSString *message = [NSString stringWithFormat:@"崩潰原因如下:\n%@\n%@",[exception reason],[[exception userInfo] objectForKey:kCaughtExceptionStackInfoKey]];NSLog(@"%@",message);UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"程序崩潰了"message:@"如果你能讓程序起死回生,那你的決定是?"delegate:selfcancelButtonTitle:@"崩就蹦吧"otherButtonTitles:@"起死回生", nil];[alert show];CFRunLoopRef runLoop = CFRunLoopGetCurrent();CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);while (!ignore) {for (NSString *mode in (__bridge NSArray *)allModes) {CFRunLoopRunInMode((CFStringRef)mode, 0.001, false);}}CFRelease(allModes);NSSetUncaughtExceptionHandler(NULL);signal(SIGABRT, SIG_DFL);signal(SIGILL, SIG_DFL);signal(SIGSEGV, SIG_DFL);signal(SIGFPE, SIG_DFL);signal(SIGBUS, SIG_DFL);signal(SIGPIPE, SIG_DFL);if ([[exception name] isEqual:kSignalExceptionName]) {kill(getpid(), [[[exception userInfo] objectForKey:kSignalKey] intValue]);} else {[exception raise];} }

因為我這里弄了一個AlertView彈窗,所以必須要回到主線程來處理。
實際上,RunLoop 相關的代碼:

CFRunLoopRef runLoop = CFRunLoopGetCurrent();CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);while (!ignore) {for (NSString *mode in (__bridge NSArray *)allModes) {CFRunLoopRunInMode((CFStringRef)mode, 0.001, false);}}CFRelease(allModes);

完全可以寫在 上面的 HandleException 回調 和 SignalHandler回調中。

第五步,寫一段會導致崩潰的代碼

我是在ViewController 中添加了一個點擊事件,弄了一個數組越界的Bug:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {NSArray *array =[NSArray array];NSLog(@"%@",[array objectAtIndex:1]); }

動態效果圖:

sunnyxx 稱之為回光返照,為什么呢?
我再一次點擊視圖,應用依然還是崩潰了,只能防止第一次崩潰。
我測試了,確實是第二次應用崩潰,未能起死回生。

文中的示例代碼都來自:RunLoopDemos中的RunLoopDemo04

轉載于:https://www.cnblogs.com/wanghang/p/6298800.html

總結

以上是生活随笔為你收集整理的RunLoop总结:RunLoop的应用场景(五)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。