一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情。
常见的Crash
分为Exception
和Signal
两种
常规的Exception
- 当触发
Exception
异常,可以使用上述方法成功拦截
Signal
异常的产生
- 当触发
Signal
异常,单凭NSSetUncaughtExceptionHandler
注册回调函数是无法拦截到的,我们需要针对Signal
进行额外的处理
Crash
分析中的Signal
:www.jianshu.com/p/3a9dc6bd5…
Signal
的回调函数
在LGUncaughtExceptionHandler
类中,增加对Signal
的处理
+ (void)installUncaughtExceptionHandler {
NSSetUncaughtExceptionHandler(&LGExceptionHandlers);
//针对Signal的处理
signal(SIGABRT, LGSignalHandler);
signal(SIGILL, LGSignalHandler);
signal(SIGSEGV, LGSignalHandler);
signal(SIGFPE, LGSignalHandler);
signal(SIGBUS, LGSignalHandler);
signal(SIGPIPE, LGSignalHandler);
}
复制代码
处理Signal
异常
进入LGSignalHandler
函数
//处理signal报错
void LGSignalHandler(int signal) {
int32_t exceptionCount = OSAtomicIncrement32(&LGUncaughtExceptionCount);
// 如果太多不用处理
if (exceptionCount > LGUncaughtExceptionCount) {
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 = [LGUncaughtExceptionHandler backtrace];
[userInfo setObject:callStack forKey:LGUncaughtExceptionHandlerAddressesKey];
[userInfo setObject:[NSNumber numberWithInt:signal] forKey:LGUncaughtExceptionHandlerSignalKey];
NSException *ex = [NSException exceptionWithName:LGUncaughtExceptionHandlerSignalExceptionName reason:description userInfo:userInfo];
//在主线程中,执行指定的方法, withObject是执行方法传入的参数
[[[LGUncaughtExceptionHandler alloc] init] performSelectorOnMainThread:@selector(lg_handleException:) withObject:ex waitUntilDone:YES];
}
复制代码
- 将
signal
一起包装到NSMutableDictionary
中 - 创建一个自定义名称和描述的
NSException
- 调用
LGUncaughtExceptionHandler
类的lg_handleException
对象方法
进入lg_handleException
方法,包含Exception
和Signa
的处理
- (void)lg_handleException:(NSException *)exception{
NSLog(@"%@", exception);
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Crash" message:nil preferredStyle:UIAlertControllerStyleAlert];
[controller addAction:[UIAlertAction actionWithTitle:@"继续执行" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}]];
[controller addAction:[UIAlertAction actionWithTitle:@"退出程序" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
self.dismissed = YES;
}]];
UIViewController *rootController = [UIApplication sharedApplication].keyWindow.rootViewController;
[rootController presentViewController:controller animated:true completion:nil];
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:LGUncaughtExceptionHandlerSignalExceptionName]) {
kill(getpid(), [[[exception userInfo] objectForKey:LGUncaughtExceptionHandlerSignalKey] intValue]);
} else {
[exception raise];
}
}
复制代码
Signa
的监听回收相应内存- 对自定义
NSException
进行特殊处理