一、Appdelagte中注冊crash記錄上報
#import "CrashHandler.h"
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[CrashHandler sharedInstance];
return YES;
}
二、CrashHandler文件
#import <Foundation/Foundation.h>
@interface CrashHandler : NSObject
{
BOOL ignore;
}
+ (instancetype)sharedInstance;
@end
#import "CrashHandler.h"
#import <UIKit/UIKit.h>
#include <libkern/OSAtomic.h>
#include <execinfo.h>
static CrashHandler *instance = nil;
NSString * const kSignalExceptionName = @"kSignalExceptionName";
NSString * const kSignalKey = @"kSignalKey";
NSString * const kCaughtExceptionStackInfoKey = @"kCaughtExceptionStackInfoKey";
void HandleException(NSException *exception);
void SignalHandler(int signal);
@implementation CrashHandler
+ (instancetype)sharedInstance {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[[self class] alloc] init];
});
return instance;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [super allocWithZone:zone];
});
return instance;
}
- (instancetype)init{
self = [super init];
if (self) {
[self setCatchExceptionHandler];
}
return self;
}
- (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);
}
+ (NSArray *)backtrace{
void* callstack[128];
int frames = backtrace(callstack, 128);
char **strs = backtrace_symbols(callstack, frames);
NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];
for (int i = 0; i < frames; i++) {
[backtrace addObject:[NSString stringWithUTF8String:strs[i]]];
}
free(strs);
return backtrace;
}
- (void)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex{
if (anIndex == 0) {
ignore = YES;
} else if (anIndex == 1) {
NSLog(@"起死回生");
}
}
- (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:self
cancelButtonTitle:@"崩就蹦吧"
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];
}
}
@end
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:kSignalExceptionName
reason:[NSString stringWithFormat:NSLocalizedString(@"Signal %d was raised.", nil),signal]
userInfo:@{kSignalKey:[NSNumber numberWithInt:signal]}];
[crashObject performSelectorOnMainThread: @selector(handleException:) withObject:customException waitUntilDone:YES];
}
@end