iOS 崩溃异常捕获

2016-07-21  本文已影响309人  黑暗森林的歌者

iOS已经提供了捕获异常的机制

NSSetUncaughtExceptionHandler

我们就创建一个捕获crash的类,其中写好分析崩溃原因的方法

头文件

#import <UIKit/UIKit.h>

@interface UncaughtExceptionHandler : NSObject{

}

@end

void HandleException(NSException *exception);
void SignalHandler(int signal);

//在didFinishLaunchingWithOptions中添加这个方法
//添加一行  
/*
  InstallUncaughtExceptionHandler();
*/
void InstallUncaughtExceptionHandler(void);

.m文件

定义

#include <libkern/OSAtomic.h>
#include <execinfo.h>

NSString * const UncaughtExceptionHandlerSignalExceptionName = @"UncaughtExceptionHandlerSignalExceptionName";
NSString * const UncaughtExceptionHandlerSignalKey = @"UncaughtExceptionHandlerSignalKey";
NSString * const UncaughtExceptionHandlerAddressesKey = @"UncaughtExceptionHandlerAddressesKey";

volatile int32_t UncaughtExceptionCount = 0;
const int32_t UncaughtExceptionMaximum = 10;

const NSInteger UncaughtExceptionHandlerSkipAddressCount = 4;
const NSInteger UncaughtExceptionHandlerReportAddressCount = 5;

实现方法

@implementation UncaughtExceptionHandler

+ (NSArray *)backtrace
{
  void* callstack[128];
  int frames = backtrace(callstack, 128);
  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;
}
- (void)handleException:(NSException *)exception
{
 //可以在这个方法中打印或者弹出alert显示出来错误信息
/*弹窗的message可以是
  [NSString stringWithFormat:NSLocalizedString(   
                @"你可以执行一些崩溃后需要做的事情.\n"  
                @"%@\n%@", nil),  
                [exception reason],    //崩溃内容 
                [[exception userInfo] objectForKey:UncaughtExceptionHandlerAddressesKey]]
*/
 CFRunLoopRef runLoop = CFRunLoopGetCurrent();
 CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
 while (!dismissed)
 {
  for (NSString *mode in (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);
 
    {
        kill(getpid(),[[[[exception userInfo] allValues] lastObject] intValue]);
    }

}

@end
void HandleException(NSException *exception)
{
 int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);
 if (exceptionCount > UncaughtExceptionMaximum)
 {
  return;
 }
 
 NSArray *callStack = [exception callStackSymbols];//堆栈调用信息
    //[UncaughtExceptionHandler backtrace];
 NSMutableDictionary *userInfo =
  [NSMutableDictionary dictionaryWithDictionary:[exception userInfo]];
 [userInfo
  setObject:callStack
  forKey:UncaughtExceptionHandlerAddressesKey];
 
 [[[[UncaughtExceptionHandler alloc] init] autorelease]
  performSelectorOnMainThread:@selector(handleException:)
  withObject:
   [NSException
    exceptionWithName:[exception name]
    reason:[exception reason]
    userInfo:userInfo]
  waitUntilDone:YES];
}

void SignalHandler(int signal)
{
      NSLog(@"handleException 4");
 int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);
 if (exceptionCount > UncaughtExceptionMaximum)
 {
  return;
 }
 
 NSMutableDictionary *userInfo =
  [NSMutableDictionary
   dictionaryWithObject:[NSNumber numberWithInt:signal]
   forKey:UncaughtExceptionHandlerSignalKey];

 NSArray *callStack = [UncaughtExceptionHandler backtrace];
 [userInfo
  setObject:callStack
  forKey:UncaughtExceptionHandlerAddressesKey];
 
 [[[[UncaughtExceptionHandler alloc] init] autorelease]
  performSelectorOnMainThread:@selector(handleException:)
  withObject:
   [NSException
    exceptionWithName:UncaughtExceptionHandlerSignalExceptionName
    reason:
     [NSString stringWithFormat:
      NSLocalizedString(@"Signal %d was raised.", nil),
      signal]
    userInfo:
     [NSDictionary
      dictionaryWithObject:[NSNumber numberWithInt:signal]
      forKey:UncaughtExceptionHandlerSignalKey]]
  waitUntilDone:YES];
}

void InstallUncaughtExceptionHandler(void)
{
 NSSetUncaughtExceptionHandler(&HandleException);
 signal(SIGABRT, SignalHandler);
 signal(SIGILL, SignalHandler);
 signal(SIGSEGV, SignalHandler);
 signal(SIGFPE, SignalHandler);
 signal(SIGBUS, SignalHandler);
 signal(SIGPIPE, SignalHandler);
}
上一篇下一篇

猜你喜欢

热点阅读