IOS程序crash捕获
来源:互联网 发布:nginx 自定义变量 编辑:程序博客网 时间:2024/04/29 16:52
IOS程序crash捕获
基础理论
Crash分为两种,一种是程序抛出的异常,没有被捕获造成的;另一种是signal类型的异常。针对未被捕获的异常可以使用NSSetUncaughtExceptionHandler系统方法来设置异常处理函数;对于signal类型的异常,需要使用signal系统方法给每种需要处理的signal类型的异常设置处理函数。如果没有为一个信号设置对应的处理函数,就会使用默认的处理函数SIG_DFL。
Signal的常见类型:
SIGABRT——程序中止信号
SIGFPE——浮点异常信号
SIGILL——非法指令异常
SIGSEGV——无效内存异常
SIGBUS——内存字节未对齐异常
SIGPIPE——socket发送失败异常
头文件”execinfo.h”声明了几个函数用于获取当前线程的函数调用堆栈,在程序出错的时候,打印出调用堆栈是非常有用的。
int backtrace(void **buffer,int size)
该函数用于获取当前线程的调用堆栈,获取的信息将被存储在buffer中,它是一个指针列表。参数size用来指定buffer中可以保存多少个指针元素。函数返回值是实际获取的指针个数,最大不超过size的大小。
char ** backtrace_symbols (void *const *buffer, int size)
backtrace_symbols将从backtrace函数中获取的信息转化为字符串数组。参数buffer应该是从backtrace函数获取的指针数组,size是该数组中的元素个数(backtrace的返回值)。函数返回值是一个指向字符串数组的指针,它的大小同buffer相同.每个字符串包含了一个相对于buffer中对应元素的可打印信息.它包括函数名,函数的偏移地址,和实际的返回地址
解决方案
这里我定义一个类UncaughtExceptionHandler处理以上提及的两种异常类型。大致思路:分别给两种类型的异常注册处理函数,然后以弹出视图的方式显示异常信息。
头文件UncaughtExceptionHandler.h
#import <Foundation/Foundation.h>@interface UncaughtExceptionHandler : NSObject{ BOOL dismissed;//是否继续程序}@end//处理未捕获的异常void HandleUncaughtException(NSException *exception);//处理信号类型的异常void HandleSignal(int signal);//为两种类型的信号注册处理函数void InstallUncaughtExceptionHandler(void);
实现文件UncaughtExceptionHandler.m
<pre name="code" class="objc">//// UncaughtExceptionHandler.m// crashTest//// Created by HuberySun on 15/11/11.// Copyright © 2015年 HuberySun. All rights reserved.//#import "UncaughtExceptionHandler.h"#import <UIKit/UIKit.h>#include <libkern/OSAtomic.h>#include <execinfo.h>NSString * const UncaughtExceptionHandlerSignalExceptionName=@"UncaughtExceptionHandlerSignalExceptionName";NSString * const UncaughtExceptionHandlerSignalKey=@"UncaughtExceptionHandlerSignalKey";NSString * const UncaughtExceptionHandlerAddressesKey=@"UncaughtExceptionHandlerAddressesKey";volatile int32_t exceptionCount = 0;const int32_t exceptionMaximum = 10;const NSInteger UncaughtExceptionHandlerReportAddressCount = 10;//指明报告多少条调用堆栈信息@interface UncaughtExceptionHandler ()<UIAlertViewDelegate>//获取堆栈指针,返回符号化之后的数组+ (NSArray *)backtrace;//处理异常2,包括抛出的异常和信号异常- (void)handleException:(NSException *)exception;@end@implementation UncaughtExceptionHandler+ (NSArray *)backtrace{ void *callStack[128];//堆栈方法数组 int frames=backtrace(callStack, 128);//从iOS的方法backtrace中获取错误堆栈方法指针数组,返回数目 char **strs=backtrace_symbols(callStack, frames);//符号化 int i; NSMutableArray *symbolsBackTrace=[NSMutableArray arrayWithCapacity:frames]; for (i=0; i<UncaughtExceptionHandlerReportAddressCount; i++) { [symbolsBackTrace addObject:[NSString stringWithUTF8String:strs[i]]]; } free(strs); return symbolsBackTrace;}- (void)handleException:(NSException *)exception{ NSString *message=[NSString stringWithFormat:@"如果点击继续,程序有可能会出现其他的问题,建议您还是点击退出按钮并重新打开\n\n异常报告:\n异常名称:%@\n异常原因:%@\n其他信息:%@\n", [exception name], [exception reason], [[exception userInfo] objectForKey:UncaughtExceptionHandlerAddressesKey]]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"抱歉,程序出现了异常", nil) message:message delegate:self cancelButtonTitle:@"退出" otherButtonTitles:@"继续", nil]; [alert show]; /////////////// CFRunLoopRef runLoop=CFRunLoopGetCurrent(); CFArrayRef allModes=CFRunLoopCopyAllModes(runLoop); NSArray *arr=(__bridge NSArray *)allModes; while (!dismissed) { for (NSString *mode in arr) { 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:UncaughtExceptionHandlerSignalExceptionName]) { kill(getpid(), [[[exception userInfo] objectForKey:UncaughtExceptionHandlerSignalKey] intValue]); } else { [exception raise]; }}- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{ if (buttonIndex==0) { dismissed=YES; }else{ dismissed=false; }}@endvoid HandleUncaughtException(NSException *exception){ int32_t exceptionCount=OSAtomicIncrement32(&exceptionCount); if (exceptionCount>exceptionMaximum) { return; } NSArray *callStack=[UncaughtExceptionHandler backtrace]; NSMutableDictionary *userInfo=[NSMutableDictionary dictionaryWithDictionary:[exception userInfo]]; [userInfo setObject:callStack forKey:UncaughtExceptionHandlerAddressesKey]; UncaughtExceptionHandler *uncaughtExceptionHandler=[[UncaughtExceptionHandler alloc] init]; NSException *uncaughtException=[NSException exceptionWithName:[exception name] reason:[exception reason] userInfo:userInfo]; [uncaughtExceptionHandler performSelectorOnMainThread:@selector(handleException:) withObject:uncaughtException waitUntilDone:YES];}void HandleSignal(int signal){ int32_t exceptionCount= OSAtomicIncrement32(&exceptionCount); if (exceptionCount>exceptionMaximum) { return; } NSMutableDictionary *userInfo=[NSMutableDictionary dictionaryWithObject:[NSNumber numberWithInt:signal] forKey:UncaughtExceptionHandlerSignalKey]; NSArray *callBack=[UncaughtExceptionHandler backtrace]; [userInfo setObject:callBack forKey:UncaughtExceptionHandlerAddressesKey]; UncaughtExceptionHandler *uncaughtExceptionHandler=[[UncaughtExceptionHandler alloc] init]; NSException *signalException=[NSException exceptionWithName:UncaughtExceptionHandlerSignalExceptionName reason:[NSString stringWithFormat:@"Signal %d was raised.",signal] userInfo:userInfo]; [uncaughtExceptionHandler performSelectorOnMainThread:@selector(handleException:) withObject:signalException waitUntilDone:YES];}void InstallUncaughtExceptionHandler(void){ NSSetUncaughtExceptionHandler(HandleUncaughtException);//设置未捕获的异常处理 //设置信号类型的异常处理 signal(SIGABRT, HandleSignal); signal(SIGILL, HandleSignal); signal(SIGSEGV, HandleSignal); signal(SIGFPE, HandleSignal); signal(SIGBUS, HandleSignal); signal(SIGPIPE, HandleSignal);}
测试
- (IBAction)OccurCrash:(id)sender { NSArray *arr=[NSArray arrayWithObjects:@"4",@"5", nil]; NSLog(@"%@",[arr objectAtIndex:3]);}
点击按钮,访问含有两个元素的数组的第三个索引位置的元素,会触发异常,弹出提示窗口,如下
商业应用解决方案
对于发布到app store的应用,大多使用第三方的Crash统计工具,比如Crashlytics
参考信息
[iOS]使用signal让app能够从容崩溃
IOS程序异常crash捕获与拦截
Linux下利用backtrace追踪函数调用堆栈以及定位段错误
- IOS程序crash捕获
- iOS程序异常crash捕获与拦截
- [IOS]程序异常crash捕获与拦截
- IOS程序异常crash捕获与拦截
- IOS程序异常crash捕获与拦截
- IOS程序异常crash捕获与拦截
- IOS程序异常crash捕获与拦截
- IOS Crash捕获
- IOS Crash捕获
- IOS开发笔记 程序异常crash捕获与拦截
- 捕获iPhone程序的Crash
- 捕获iPhone程序的Crash
- iOS Swift Crash的捕获
- iOS Swift Crash的捕获
- IOS开发笔记(5)程序异常crash捕获与拦截
- IOS开发笔记(5)程序异常crash捕获与拦截
- IOS开发笔记(5)程序异常crash捕获与拦截
- 程序异常crash捕获与拦截
- svn Previous operation has not finished
- unity中实现断点续传功能
- UITabBarController UITabBarItem 终极一法
- Burpsuite sqlmap插件
- 二十二天
- IOS程序crash捕获
- nginx在Linux搭建环境
- 浅谈淘宝搜索排序
- Burp Suite使用介绍
- 【Mark】SourceInsight 删除汉字时半个汉字 乱码问题 的补丁
- 32程序仿真时出错,复位按钮变暗
- 在android studio上使用小米真机调试
- JS基础学习笔记
- Redis学习笔记(二)