iOS 捕获Crash方法

  • iOS开发无法避免程序Crash问题,开发过程中可以用调试技术捕获Crash进行修复,但是发布到App Store后,无法抓到这些问题,因此目前国内友盟、听云等公司抓到Crash后将Crash时的堆栈上传到他们服务器上,并可以通过dSYM文件找到Crash的方法接口。

  • 当然我们自己也可以做到,首要问题是怎么抓到这些Crash原因和堆栈列表。iOS下面最常见的就是objective-c的NSException(通过@throw抛出,比如,NSArray访问元素越界、添加空对象等等)

  • Crash堆栈


    iOS 捕获Crash方法_第1张图片
    iOS Crash堆栈

设置方法

  • 1.导入头文件
#include 
#include 
  • 2.设置Crash捕获
- (void)initHandler {
    
    struct sigaction newSignalAction;
    memset(&newSignalAction, 0,sizeof(newSignalAction));
    newSignalAction.sa_handler = &signalHandler;
    sigaction(SIGABRT, &newSignalAction, NULL);
    sigaction(SIGILL, &newSignalAction, NULL);
    sigaction(SIGSEGV, &newSignalAction, NULL);
    sigaction(SIGFPE, &newSignalAction, NULL);
    sigaction(SIGBUS, &newSignalAction, NULL);
    sigaction(SIGPIPE, &newSignalAction, NULL);
    
    //异常时调用的函数
    NSSetUncaughtExceptionHandler(&handleExceptions);
}
  • 3.异常信息
void handleExceptions(NSException *exception) {
    NSLog(@"exception = %@",exception);
    NSLog(@"callStackSymbols = %@",[exception callStackSymbols]);
}

void signalHandler(int sig) {
    //最好不要写,可能会打印太多内容
    NSLog(@"signal = %d", sig);
}
  • 4.将异常信息同步到自己服务器上
    这样就可以抓到用户使用程序时的Crash了。

实例

  • 1.在应用程序启动时初始化设置捕获,在以下方法中调用initHandler方法进行设置。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions```

- 2.写个异常程序验证,在某个控制器的```viewDidLoad```方法中写以下代码。

NSMutableArray *array = [NSMutableArray array];
[array addObject:nil];

- 3.运行代码

2016-07-10 15:44:01.148 iOSCrash[37234:6862176] exception = *** -[__NSArrayM insertObject:atIndex:]: object cannot be nil
2016-07-10 15:44:01.149 iOSCrash[37234:6862176] callStackSymbols = (
0 CoreFoundation 0x000000010ca89d85 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010c4fddeb objc_exception_throw + 48
2 CoreFoundation 0x000000010c94acc5 -[__NSArrayM insertObject:atIndex:] + 901
3 iOSCrash 0x000000010bffb80f -[ViewController viewDidLoad] + 111
4 UIKit 0x000000010cfda984 -[UIViewController loadViewIfRequired] + 1198
5 UIKit 0x000000010cfdacd3 -[UIViewController view] + 27
6 UIKit 0x000000010ceb0fb4 -[UIWindow addRootViewControllerViewIfPossible] + 61
7 UIKit 0x000000010ceb169d -[UIWindow _setHidden:forced:] + 282
8 UIKit 0x000000010cec3180 -[UIWindow makeKeyAndVisible] + 42
9 UIKit 0x000000010ce37ed9 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 4131
10 UIKit 0x000000010ce3e568 -[UIApplication _runWithMainScene:transitionContext:completion:] + 1769
11 UIKit 0x000000010ce3b714 -[UIApplication workspaceDidEndTransaction:] + 188
12 FrontBoardServices 0x000000010f8a88c8 FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK + 24
13 FrontBoardServices 0x000000010f8a8741 -[FBSSerialQueue _performNext] + 178
14 FrontBoardServices 0x000000010f8a8aca -[FBSSerialQueue _performNextFromRunLoopSource] + 45
15 CoreFoundation 0x000000010c9af301 CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 17
16 CoreFoundation 0x000000010c9a522c __CFRunLoopDoSources0 + 556
17 CoreFoundation 0x000000010c9a46e3 __CFRunLoopRun + 867
18 CoreFoundation 0x000000010c9a40f8 CFRunLoopRunSpecific + 488
19 UIKit 0x000000010ce3af21 -[UIApplication _run] + 402
20 UIKit 0x000000010ce3ff09 UIApplicationMain + 171
21 iOSCrash 0x000000010bffbb6f main + 111
22 libdyld.dylib 0x000000010f26392d start + 1
)

- 4.分析Crash

>4.1 从```exception```中得知Crash原因为Array中写了一个为nil的Object。
>4.2 从```callStackSymbols```堆栈符号中找到Crash的是第2条信息,堆栈列表可以理解为第0条为正在运行的,而该列表的第22是最早运行的,因此我们可以Crash的那条往下看可以知道这条Crash发生在```[ViewController viewDidLoad]```,即```ViewController```控制器的```viewDidLoad```方法中。

- 5.注意事项

>5.1 由于```NSSetUncaughtExceptionHandler```是```set```方法,所以只能设置一次,市面上很多抓Crash的库都会设置这个方法,因此,如果你用了UMeng Crash,Bugly(腾讯云内继承Bugly)等工具的话,最好不要自己设置,会影响Crash上报。

- **如果文章对你有帮助,请点下“喜欢”吧,感谢!**

你可能感兴趣的:(iOS 捕获Crash方法)