iOS 异常捕获学习
来源:互联网 发布:为知笔记vip破解版 编辑:程序博客网 时间:2024/05/16 13:39
iOS 异常捕获学习
头文件
#import <UIKit/UIKit.h>@interface CrashCatch : NSObject+ (void)installUncaughtExceptionHandler;+ (void)crashTest:(NSUInteger)index;@end
实现文件
#import "CrashCatch.h"#include <libkern/osatomic.h>#include <execinfo.h>NSString * const UEHSignalExceptionName = @"UncaughtExceptionHandlerSignalExceptionName";NSString * const UEHSignalKey = @"UncaughtExceptionHandlerSignalKey";NSString * const UEHAddressesKey = @"UncaughtExceptionHandlerAddressesKey";NSString * const UEHFileKey = @"UncaughtExceptionHandlerFileKey";volatile int32_t UncaughtExceptionCount = 0;const int32_t UncaughtExceptionMaximum = 10;const NSInteger UncaughtExceptionHandlerSkipAddressCount = 4;const NSInteger UncaughtExceptionHandlerReportAddressCount = 5;void UncaughtExceptionHandler(NSException *exception);void MySignalHandler(int signal);/** The exception handler that was in place before we installed ours. */static NSUncaughtExceptionHandler* g_previousUncaughtExceptionHandler;@implementation CrashCatch+ (void)installUncaughtExceptionHandler{ //获取其它工具注册的handler g_previousUncaughtExceptionHandler = NSGetUncaughtExceptionHandler(); //系统异常捕获 NSSetUncaughtExceptionHandler (&UncaughtExceptionHandler); //信号量截断 signal(SIGABRT, MySignalHandler); signal(SIGILL, MySignalHandler); signal(SIGSEGV, MySignalHandler); signal(SIGFPE, MySignalHandler); signal(SIGBUS, MySignalHandler); signal(SIGPIPE, MySignalHandler);}//异常处理方法- (void)handleException:(NSException *)exception{ NSDictionary *userInfo=[exception userInfo]; [self save:exception to:[userInfo objectForKey:UEHFileKey]]; //注册其它工具的handler if (g_previousUncaughtExceptionHandler != NULL) { g_previousUncaughtExceptionHandler(exception); } //恢复对信号的系统默认处理 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:UEHSignalExceptionName]) { kill(getpid(), [[[exception userInfo] objectForKey:UEHSignalKey] intValue]); } else { [exception raise]; }}//获取函数堆栈信息+ (NSArray *)backtrace { void *callstack[128]; //用于获取当前线程的函数调用堆栈,返回实际获取的指针个数 int frames = backtrace(callstack, 128); //从backtrace函数获取的信息转化为一个字符串数组 char **strs = backtrace_symbols(callstack, frames); int i; NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames]; for (i = UncaughtExceptionHandlerSkipAddressCount; i < UncaughtExceptionHandlerSkipAddressCount+UncaughtExceptionHandlerReportAddressCount; i++) { [backtrace addObject:[NSString stringWithUTF8String:strs[i]]]; } free(strs); return backtrace;}//获取应用信息+ (NSString *)getAppInfo{ NSString *appInfo = [NSString stringWithFormat: @"----------------------------------------\n" @"Application : %@ %@(%@)\n" @"Device Model : %@\n" @"OS Version : %@ %@\n" @"----------------------------------------\n", [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"], [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"], [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"], [UIDevice currentDevice].model, [UIDevice currentDevice].systemName, [UIDevice currentDevice].systemVersion]; NSLog(@"AppInfo: %@", appInfo); return appInfo;}- (void)save:(NSException *)exception to:(NSString *)file{ // 异常堆栈信息 NSArray *stackArray = exception.userInfo[UEHAddressesKey]; // 异常原因 NSString *reason = [exception reason]; // 异常名称 NSString *name = [exception name]; NSString *exceptionInfo = [NSString stringWithFormat: @"----------------------------------------\n" @"Exception Reason : %@\n" @"Exception Name : %@\n" @"Exception Stack : \n%@\n" @"----------------------------------------\n", reason, name, stackArray]; NSLog(@"%@", exceptionInfo); NSLog(@">>>%@", [CrashCatch backtrace]); NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) [0] stringByAppendingPathComponent:file]; if (![[NSFileManager defaultManager] fileExistsAtPath:path]){ [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil]; } NSTimeInterval timeInterval = [[NSDate date] timeIntervalSince1970]; NSString *savePath = [path stringByAppendingFormat:@"/error_%lld.log", (int64_t)timeInterval]; NSError *error = nil; BOOL didWrite = [exceptionInfo writeToFile:savePath atomically:YES encoding:NSUTF8StringEncoding error:&error]; if (didWrite) { NSLog(@"Save sucess:%@", savePath); }else { NSLog(@"Save failed:%@", error); } /** * 把异常崩溃信息发送至开发者邮件 */ NSMutableString *mailUrl = [NSMutableString string]; [mailUrl appendString:@"mailto:example@gmail.com"]; [mailUrl appendString:@"?subject=Report Crash"]; [mailUrl appendFormat:@"&body=%@", exceptionInfo]; // 打开地址 NSString *mailPath = [mailUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:mailPath]];}+ (void)crashTest:(NSUInteger)index { if (index == 0) { //常见异常1---不存在方法引用 [self performSelector:@selector(thisMthodDoesNotExist) withObject:nil]; }else if (index == 1) { //常见异常2---键值对引用nil [[NSMutableDictionary dictionary] setObject:nil forKey:@"nil"]; }else if (index == 2) { //常见异常3---数组越界 [[NSArray array] objectAtIndex:1]; }else if (index == 3) { //常见异常4---memory warning 级别3以上 [[[CrashCatch alloc] init] performSelector:@selector(otherCrash) withObject:nil]; }}- (void)otherCrash { //}@endvoid UncaughtExceptionHandler (NSException *exception){ //递增的一个全局计数器,很快很安全,防止并发数太大 int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount); if (exceptionCount > UncaughtExceptionMaximum) { return; } NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:[exception userInfo]]; NSArray *callStack = exception.callStackSymbols; [userInfo setObject:callStack forKey:UEHAddressesKey]; [userInfo setObject:@"ObjCCrash" forKey:UEHFileKey]; NSException *exp = [NSException exceptionWithName:[exception name] reason:[exception reason] userInfo:userInfo]; [[[CrashCatch alloc] init] performSelectorOnMainThread:@selector(handleException:) withObject:exp waitUntilDone:YES];}//Signal处理方法void MySignalHandler(int signal){ //递增的一个全局计数器,很快很安全,防止并发数太大 int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount); if (exceptionCount > UncaughtExceptionMaximum) { return; } NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:@{UEHSignalKey : @(signal)}]; NSArray *callStack = [CrashCatch backtrace]; [userInfo setObject:callStack forKey:UEHAddressesKey]; [userInfo setObject:@"SignalCrash" forKey:UEHFileKey]; NSString *reson = [NSString stringWithFormat:NSLocalizedString(@"Signal %d was raised.\n %@", nil), signal, [CrashCatch getAppInfo]]; NSException *exp = [NSException exceptionWithName:UEHSignalExceptionName reason:reson userInfo:userInfo]; [[[CrashCatch alloc] init] performSelectorOnMainThread:@selector(handleException:) withObject:exp waitUntilDone:YES];}
阅读全文
0 0
- iOS 异常捕获学习
- iOS异常捕获相关
- ios捕获异常
- iOS 异常捕获
- iOS之捕获异常
- ios 程序异常捕获
- ios异常捕获
- ios 捕获异常
- iOS异常捕获
- ios异常捕获
- iOS捕获应用异常
- iOS异常捕获
- iOS异常捕获
- iOS捕获异常代码
- iOS 捕获系统外异常
- IOS 捕获异常工具UncaughtExceptionHandler
- iOS 捕获系统外异常
- iOS 捕获系统外异常
- 01_Python特征
- android检测不到手机设备
- 02_Python文件类型
- java“+”号
- JSF复习系列(2)--迭代器的直观体现dataTable使用详解
- iOS 异常捕获学习
- 03_Python变量
- 2017.06.24【NOIP提高组】模拟赛B组
- python 读取文件时报错UnicodeDecodeError: 'gbk' codec can't decode byte 0x80 in position 205: illegal multib
- 利用Echarts制作地图(一)
- pid参数整定计算
- 是否二叉搜索树
- 04_Python变量的数据类型
- hdu2660