麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 系統 > iOS > 正文

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

2019-10-21 18:40:05
字體:
來源:轉載
供稿:網友

前言

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

實現效果如圖:

iOS,程序異常,Crash,友好化

效果實現:

iOS,程序異常,Crash,友好化

用法:

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收集操作,例如上傳服務器等。

源碼下載

總結

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


注:相關教程知識閱讀請移步到IOS開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 亚洲特黄a级毛片在线播放 久久久入口 | 在线1区| 成人在线观看免费观看 | 超碰97在线人人 | 国产资源在线观看视频 | 极品销魂一区二区三区 | 国外成人在线视频 | 国产精品久久久久久久av | 无遮挡一级毛片视频 | 欧美日韩亚洲另类 | 久久av免费 | 久草手机在线 | 91精品国产99久久久久久红楼 | 亚洲天堂中文字幕在线观看 | av日韩在线免费观看 | 一区二区久久精品66国产精品 | www.91视频com | 国产成人精品无人区一区 | 色av成人天堂桃色av | 国产精品久久久久久影院8一贰佰 | 羞羞视频免费网站男男 | 99视频在线观看视频 | 亚洲欧美国产精品va在线观看 | 一区二区三区欧洲 | 九九热在线观看视频 | 久草视频2 | 日韩黄色片网站 | 91av在线免费 | 得得啪在线视频 | 一级裸体视频 | 国产午夜精品久久久 | 欧美精品 | 欧美日韩大片在线观看 | 午夜视频在线观看免费视频 | 一级大片一级一大片 | 欧美一级片网站 | 成年人在线免费 | 黄色片小说 | 激情视频免费观看 | 欧美成人一级 | 国产精品美女久久久免费 |