IOS利用解体始终是一个很苦恼的问题,而解体的同时又未获取bug起因,更令人苦恼。
好在苹果自带的crash检测api,以及runloop能够让利用复活一次,不过第二次依旧会解体,然而还是一个很实用的小技巧。
以下是IOS解体复活的类和应用办法
#import "CrashHandler.h"//Appdelagte中注册crash记录上报- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. [CrashHandler sharedInstance]; return YES;}//.h文件#import <Foundation/Foundation.h>@interface CrashHandler : NSObject{ BOOL ignore;}+ (instancetype)sharedInstance;@end//.m文件#import "CrashHandler.h"#import <UIKit/UIKit.h>#include <libkern/OSAtomic.h>#include <execinfo.h>NSString * const kSignalExceptionName = @"kSignalExceptionName";NSString * const kSignalKey = @"kSignalKey";NSString * const kCaughtExceptionStackInfoKey = @"kCaughtExceptionStackInfoKey";void HandleException(NSException *exception);void SignalHandler(int signal);@implementation CrashHandlerstatic CrashHandler *instance = nil;+ (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]; }}@endvoid 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];}