国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > iOS > 正文

iOS中程序異常Crash友好化處理詳解

2020-07-26 02:25:00
字體:
來源:轉載
供稿:網友

前言

前兩天接到個面試,面試官問到上線的app怎么避免閃退,首先想到的就是在編碼的時候進行各種容錯,但貌似并不是面試官想要的答案,所以表現的很糟糕。今天有時間就來整理一下,希望有所幫助。

實現效果如圖:


效果實現:


用法:

1.將截圖的中CatchedHelper文件夾拖到你的項目工程中。

2.在AppDelegate.m中找到以下方法并如下添加代碼:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch.  [UncaughtExceptionHandler installUncaughtExceptionHandler:YES showAlert:YES]; return YES;}

以上代碼就可以實現稍微友好一點的crash攔截處理。

代碼解釋:

UncaughtExceptionHandler.h主要代碼:

#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>@interface UncaughtExceptionHandler : NSObject/*! * 異常的處理方法 * * @param install 是否開啟捕獲異常 * @param showAlert 是否在發生異常時彈出alertView */+ (void)installUncaughtExceptionHandler:(BOOL)install showAlert:(BOOL)showAlert;@end

UncaughtExceptionHandler.m文件主要的代碼如下:

1.發送異常信號

/* * 異常的處理方法 * * @param install  是否開啟捕獲異常 * @param showAlert 是否在發生異常時彈出alertView */+ (void)installUncaughtExceptionHandler:(BOOL)install showAlert:(BOOL)showAlert {    if (install && showAlert) {    [[self alloc] alertView:showAlert];  }    NSSetUncaughtExceptionHandler(install ? HandleException : NULL);  signal(SIGABRT, install ? SignalHandler : SIG_DFL);  signal(SIGILL, install ? SignalHandler : SIG_DFL);  signal(SIGSEGV, install ? SignalHandler : SIG_DFL);  signal(SIGFPE, install ? SignalHandler : SIG_DFL);  signal(SIGBUS, install ? SignalHandler : SIG_DFL);  signal(SIGPIPE, install ? SignalHandler : SIG_DFL);}

產生上述的signal的時候就會調用我們定義的SignalHandler來處理異常。

ps: NSSetUncaughtExceptionHandler就是iOS SDK中提供的一個現成的函數,用來捕獲異常的方法,使用方便。但它不能捕獲拋出的signal,所以定義了SignalHandler方法。

2.處理異常

void HandleException(NSException *exception) {      int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);  // 如果太多不用處理  if (exceptionCount > UncaughtExceptionMaximum) {    return;  }    //獲取調用堆棧  NSArray *callStack = [exception callStackSymbols];  NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:[exception userInfo]];  [userInfo setObject:callStack forKey:UncaughtExceptionHandlerAddressesKey];    //在主線程中,執行制定的方法, withObject是執行方法傳入的參數  [[[UncaughtExceptionHandler alloc] init]   performSelectorOnMainThread:@selector(handleException:)   withObject:   [NSException exceptionWithName:[exception name]               reason:[exception reason]              userInfo:userInfo]   waitUntilDone:YES];}

該方法就是對應NSSetUncaughtExceptionHandler的處理,只要方法關聯到這個函數,那么發生相應錯誤時會自動調用該函數,調用時會傳入exception參數。獲取異常后會將捕獲的異常傳入最終調用處理的handleException函數。

3.無法捕獲的signal處理

//處理signal報錯void SignalHandler(int signal) {    int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);  // 如果太多不用處理  if (exceptionCount > UncaughtExceptionMaximum) {    return;  }    NSString* description = nil;  switch (signal) {    case SIGABRT:      description = [NSString stringWithFormat:@"Signal SIGABRT was raised!/n"];      break;    case SIGILL:      description = [NSString stringWithFormat:@"Signal SIGILL was raised!/n"];      break;    case SIGSEGV:      description = [NSString stringWithFormat:@"Signal SIGSEGV was raised!/n"];      break;    case SIGFPE:      description = [NSString stringWithFormat:@"Signal SIGFPE was raised!/n"];      break;    case SIGBUS:      description = [NSString stringWithFormat:@"Signal SIGBUS was raised!/n"];      break;    case SIGPIPE:      description = [NSString stringWithFormat:@"Signal SIGPIPE was raised!/n"];      break;    default:      description = [NSString stringWithFormat:@"Signal %d was raised!",signal];  }    NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];  NSArray *callStack = [UncaughtExceptionHandler backtrace];  [userInfo setObject:callStack forKey:UncaughtExceptionHandlerAddressesKey];  [userInfo setObject:[NSNumber numberWithInt:signal] forKey:UncaughtExceptionHandlerSignalKey];    //在主線程中,執行指定的方法, withObject是執行方法傳入的參數  [[[UncaughtExceptionHandler alloc] init]   performSelectorOnMainThread:@selector(handleException:)   withObject:   [NSException exceptionWithName:UncaughtExceptionHandlerSignalExceptionName               reason: description              userInfo: userInfo]   waitUntilDone:YES];}

以上方法是對于捕獲不到的signal信號進行處理,列出常見的異常類型。

4.堆棧調用

//獲取調用堆棧+ (NSArray *)backtrace {    //指針列表  void* callstack[128];  //backtrace用來獲取當前線程的調用堆棧,獲取的信息存放在這里的callstack中  //128用來指定當前的buffer中可以保存多少個void*元素  //返回值是實際獲取的指針個數  int frames = backtrace(callstack, 128);  //backtrace_symbols將從backtrace函數獲取的信息轉化為一個字符串數組  //返回一個指向字符串數組的指針  //每個字符串包含了一個相對于callstack中對應元素的可打印信息,包括函數名、偏移地址、實際返回地址  char **strs = backtrace_symbols(callstack, frames);    int i;  NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];  for (i = 0; i < frames; i++) {        [backtrace addObject:[NSString stringWithUTF8String:strs[i]]];  }  free(strs);    return backtrace;}

backtrace是Linux下用來追蹤函數調用堆棧以及定位段錯誤的函數。

5.使用UIAlerView進行友好化提示

- (void)handleException:(NSException *)exception {    [self validateAndSaveCriticalApplicationData:exception];    if (!showAlertView) {    return;  }  #pragma clang diagnostic push#pragma clang diagnostic ignored "-Wdeprecated-declarations"  UIAlertView *alert =  [[UIAlertView alloc]   initWithTitle:@"出錯啦"   message:[NSString stringWithFormat:@"你可以嘗試繼續操作,但是應用可能無法正常運行./n"]   delegate:self   cancelButtonTitle:@"退出"   otherButtonTitles:@"繼續", nil];  [alert show];#pragma clang diagnostic pop    CFRunLoopRef runLoop = CFRunLoopGetCurrent();  CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);    while (!self.dismissed) {    //點擊繼續    for (NSString *mode in (__bridge NSArray *)allModes) {      //快速切換Mode      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:UncaughtExceptionHandlerSignalExceptionName]) {        kill(getpid(), [[[exception userInfo] objectForKey:UncaughtExceptionHandlerSignalKey] intValue]);      } else {        [exception raise];  }}

在這里你可以做自己的crash收集操作,例如上傳服務器等。

源碼下載

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對武林網的支持。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 合阳县| 承德市| 静海县| 綦江县| 临安市| 横山县| 鱼台县| 阳原县| 稷山县| 江阴市| 宜春市| 磐安县| 台前县| 阜南县| 东安县| 华宁县| 山东省| 黔江区| 南阳市| 沁源县| 仪陇县| 辛集市| 德清县| 全椒县| 郓城县| 茂名市| 新宁县| 尼勒克县| 颍上县| 尚志市| 方山县| 荣昌县| 固安县| 墨竹工卡县| 灌南县| 绵竹市| 胶州市| 涞源县| 通辽市| 双牌县| 丰镇市|