IOS崩溃 异常处理(NSSetUncaughtExceptionHandler)
- iOS已发布应用中对异常信息捕获和处理
- 代码下载地址:http://download.csdn.net/detail/daiyelang/6740205
- iOS开发中我们会遇到程序抛出异常退出的情况,如果是在调试的过程中,异常的信息是一目了然,但是如果是在已经发布的程序中,获取异常的信息有时候是比较困难的。
- iOS提供了异常发生的处理API,我们在程序启动的时候可以添加这样的Handler,这样的程序发生异常的时候就可以对这一部分的信息进行必要的处理,适时的反馈给开发者。
- 不足的地方是,并不是所有的程序崩溃都是由于发生可以捕捉的异常的,有些时候是因为内存等一些其他的错误导致程序的崩溃,这样的信息是不在这里体现的。
- 我做了一个简单的类,进行很基本的操作,可以添加和获取Handler,捕获到异常后将信息写入到app的Documens下的Exception.txt中。
- 其实还有很多的处理的办法。
- l 比如可以在程序下一次起来的时候读取这个异常文件发生到服务端。
- l 或者直接就是在处理代码中用openurl的方式(mailto:)调用发送邮件的方式,将异常信息直接变成邮件发送到指定地址。
- 以下是完整的代码实现。
- 使用场景示例:
- #pragma mark -
- #pragma mark Application lifecycle
- - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
- // Override point for customization after application launch.
- [window makeKeyAndVisible];
- [NdUncaughtExceptionHandler setDefaultHandler];
- NSArray *array = [NSArray arrayWithObject:@"there is only one objective in this arary,call index one, app will crash and throw an exception!"];
- NSLog(@"%@", [array objectAtIndex:1]);
- return YES;
- }
- 基本接口展示:
- #import <Foundation/Foundation.h>
- @interface NdUncaughtExceptionHandler : NSObject {
- }
- + (void)setDefaultHandler;
- + (NSUncaughtExceptionHandler*)getHandler;
- @end
- //还可以选择设置自定义的handler,让用户取选择
- 接口实现展示
- #import "NdUncaughtExceptionHandler.h"
- NSString *applicationDocumentsDirectory() {
- return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
- }
- void UncaughtExceptionHandler(NSException *exception) {
- NSArray *arr = [exception callStackSymbols];
- NSString *reason = [exception reason];
- NSString *name = [exception name];
- NSString *url = [NSString stringWithFormat:@"=============异常崩溃报告=============\nname:\n%@\nreason:\n%@\ncallStackSymbols:\n%@",
- name,reason,[arr componentsJoinedByString:@"\n"]];
- NSString *path = [applicationDocumentsDirectory() stringByAppendingPathComponent:@"Exception.txt"];
- [url writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];
- //除了可以选择写到应用下的某个文件,通过后续处理将信息发送到服务器等
- //还可以选择调用发送邮件的的程序,发送信息到指定的邮件地址
- //或者调用某个处理程序来处理这个信息
- }
- @implementation NdUncaughtExceptionHandler
- -(NSString *)applicationDocumentsDirectory {
- return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
- }
- + (void)setDefaultHandler
- {
- NSSetUncaughtExceptionHandler (&UncaughtExceptionHandler);
- }
- + (NSUncaughtExceptionHandler*)getHandler
- {
- return NSGetUncaughtExceptionHandler();
- }
- @end
- 异常崩溃报告:
- =============异常崩溃报告=============
- name:
- NSRangeException
- reason:
- *** -[NSArray objectAtIndex:]: index 1 beyond bounds [0 .. 0]
- callStackSymbols:
- 0 CoreFoundation 0x02393919 __exceptionPreprocess + 185
- 1 libobjc.A.dylib 0x024e15de objc_exception_throw + 47
- 2 CoreFoundation 0x0238958c -[__NSArrayI objectAtIndex:] + 236
- 3 UncaughtE 0x000022e8 -[UncaughtEAppDelegate application:didFinishLaunchingWithOptions:] + 157
- 4 UIKit 0x002b8543 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1163
- 5 UIKit 0x002ba9a1 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 346
- 6 UIKit 0x002c4452 -[UIApplication handleEvent:withNewEvent:] + 1958
- 7 UIKit 0x002bd074 -[UIApplication sendEvent:] + 71
- 8 UIKit 0x002c1ac4 _UIApplicationHandleEvent + 7495
- 9 GraphicsServices 0x02bf9afa PurpleEventCallback + 1578
- 10 CoreFoundation 0x02374dc4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 52
- 11 CoreFoundation 0x022d5737 __CFRunLoopDoSource1 + 215
- 12 CoreFoundation 0x022d29c3 __CFRunLoopRun + 979
- 13 CoreFoundation 0x022d2280 CFRunLoopRunSpecific + 208
- 14 CoreFoundation 0x022d21a1 CFRunLoopRunInMode + 97
- 15 UIKit 0x002ba226 -[UIApplication _run] + 625
- 16 UIKit 0x002c5b58 UIApplicationMain + 1160
- 17 UncaughtE 0x00002228 main + 102
- 18 UncaughtE 0x000021b9 start + 53
- 不足的地方是,并不是所有的程序崩溃都是由于发生可以捕捉的异常的,有些时候引起崩溃的大多数原因如:内存访问错误,重复释放等错误就无能为力了,因为这种错误它抛出的是Signal,所以必须要专门做Signal处理。首先定义一个UncaughtExceptionHandler类,.h头文件的代码如下:
- UncaughtExceptionHandler类,.h头文件的代码如下:
- 1
- 2
- 3
- 4
- 5
- 6
- #import
- @interface UncaughtExceptionHandler : NSObject{
- BOOL dismissed;
- }
- @end
- 1
- void InstallUncaughtExceptionHandler();
- 然后在.mm文件实现InstallUncaughtExceptionHandler(),如下:
- void InstallUncaughtExceptionHandler(){
- signal(SIGABRT, MySignalHandler);
- signal(SIGILL, MySignalHandler);
- signal(SIGSEGV, MySignalHandler);
- signal(SIGFPE, MySignalHandler);
- signal(SIGBUS, MySignalHandler);
- signal(SIGPIPE, MySignalHandler);
- }
- 这样,当应用发生错误而产生上述Signal后,就将会进入我们自定义的回调函数MySignalHandler。为了得到崩溃时的现场信息,还可以加入一些获取CallTrace及设备信息的代码,.mm文件的完整代码如下:
- #import "UncaughtExceptionHandler.h"
- #include #include
- 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);
- charchar **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)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex
- {
- if (anIndex == 0)
- {
- dismissed = YES;
- }
- }
- - (void)handleException:(NSException *)exception
- {
- UIAlertView *alert =
- [[[UIAlertView alloc]
- initWithTitle:NSLocalizedString(@"Unhandled exception", nil)
- message:[NSString stringWithFormat:NSLocalizedString(
- @"You can try to continue but the application may be unstable.\n"
- @"%@\n%@", nil),
- [exception reason],
- [[exception userInfo] objectForKey:UncaughtExceptionHandlerAddressesKey]]
- delegate:self
- cancelButtonTitle:NSLocalizedString(@"Quit", nil)
- otherButtonTitles:NSLocalizedString(@"Continue", nil), nil nil]
- autorelease];
- [alert show];
- 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);
- if ([[exception name] isEqual:UncaughtExceptionHandlerSignalExceptionName])
- {
- <span style="white-space:pre"> </span>kill(getpid(), [[[exception userInfo] objectForKey:UncaughtExceptionHandlerSignalKey] intValue]);
- }
- else
- {
- [exception raise];
- }
- }
- @end
- NSString* getAppInfo() { NSString *appInfo = [NSString stringWithFormat:@"App : %@ %@(%@)\nDevice : %@\nOS Version : %@ %@\nUDID : %@\n", [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"], [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"], [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"], [UIDevice currentDevice].model, [UIDevice currentDevice].systemName, [UIDevice currentDevice].systemVersion, [UIDevice currentDevice].uniqueIdentifier]; NSLog(@"Crash!!!! %@", appInfo); return appInfo; } void MySignalHandler(int signal) { 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.\n"
- @"%@", nil),
- signal, getAppInfo()]
- userInfo:
- [NSDictionary
- dictionaryWithObject:[NSNumber numberWithInt:signal]
- forKey:UncaughtExceptionHandlerSignalKey]]
- waitUntilDone:YES];
- }
- void InstallUncaughtExceptionHandler()
- {
- signal(SIGABRT, MySignalHandler);
- signal(SIGILL, MySignalHandler);
- signal(SIGSEGV, MySignalHandler);
- signal(SIGFPE, MySignalHandler);
- signal(SIGBUS, MySignalHandler);
- signal(SIGPIPE, MySignalHandler);
- }
- 在应用自身的 didFinishLaunchingWithOptions 前,加入一个函数:
- - (void)installUncaughtExceptionHandler
- {
- InstallUncaughtExceptionHandler();
- }
- 最后,在 didFinishLaunchingWithOptions 中加入这一句代码就行了:
- 1
- [self InstallUncaughtExceptionHandler];
- 现在,基本上所有崩溃都能Hold住了。崩溃时将会显示出如下的对话框:
- iOS开发23:通过归档永久存储数据 - 双子座的个人页面 - 开源中国社区
- 这样在崩溃时还能从容地弹出对话框,比起闪退来,用户也不会觉得那么不爽。然后在下次启动时还可以通过邮件来发送Crash文件到邮箱,这就看各个应用的需求了。
IOS崩溃 异常处理(NSSetUncaughtExceptionHandler)的更多相关文章
- (转)IOS崩溃 异常处理(NSSetUncaughtExceptionHandler)
iOS已发布应用中对异常信息捕获和处理 代码下载地址:http://download.csdn.net/detail/daiyelang/6740205 iOS开发中我们会遇到程序抛出异常退出的情况, ...
- iOS - 崩溃异常处理(1)
https://www.jianshu.com/p/4d32664dcfdb 一.关于崩溃 闪退估计是我们最不想看到的,对于用户而言,马上就能产生一种不悦,对于投资方而言,也会产生对技术实力的不信任感 ...
- iOS崩溃调试的使用和技巧总结
在iOS开发调试过程中以及上线之后,程序经常会出现崩溃的问题.简单的崩溃还好说,复杂的崩溃就需要我们通过解析Crash文件来分析了,解析Crash文件在iOS开发中是比较常见的. 现在网上有很多关于解 ...
- Android&iOS崩溃堆栈上报
Android&iOS崩溃堆栈上报 原文地址:http://www.cnblogs.com/songcf/p/4885468.html 通过崩溃捕获和收集,可以收集到已发布应用(游戏)的异常, ...
- iOS崩溃日志ips文件解析
iOS崩溃日志ips文件解析 一 简介 测试组的同事在进行稳定性测试时,通常会遇到一些崩溃,然后他们会将这些崩溃日志(一般是ips格式的文件)反馈给开发进行分析,但是这些ips文件中的内容通常是如下 ...
- 详解没有dSYM文件 如何解析iOS崩溃日志
Xcode支持崩溃日志自动符号化,前提是本地有当时Build/Archive生成的dSYM文件,iOS崩溃日志符号化后,可以帮助开发者更好的定位问题,但如果dSYM文件丢失或拿到的崩溃日志不是标准的c ...
- 转: iOS崩溃堆栈符号表使用与用途
转:http://bugly.qq.com/blog/?p=119 iOS崩溃堆栈符号化,定位问题分分钟搞定! 2015.3.16 腾讯Bugly 微信分享 最近一段时间,在跟开发者沟通过程中,萝 ...
- iOS 崩溃日志分析(个人总结,最实用)
iOS 崩溃日志分析(个人总结,最实用) 要分析奔溃日志需要三个文件:crash日志,symbolicatecrash分析工具,.dSYM符号集 0. 在桌面创建一个crash文件夹 1. 需要Xco ...
- iOS崩溃日志
今天看crash report ,有这样两个crash: 调用 stopUpdatingLocation 函数的是一个CLLocationManager 类型的对象,为什么报错的时候会把这个对象转成N ...
随机推荐
- 【Java】Java_16 控制循环结构Break、Continue、Return
1.break break用于完全结束一个循环,跳出循环体.不管是哪种循环,一旦在循环体中遇到break,系统将完全结束该循环 在Java中是的标签定义,标签就是一个紧跟着英文冒号(:)的标识符 代码 ...
- 【Java】Java_13 分支结构
Java中常见的两种分支结构: <1>If语句:使用布尔表达式或者布尔类型值作为分支条件来进行分支控制. <2>switch语句:对多个整形值进行匹配,从而实现分支控制. 1. ...
- Array,Vector,List,Deque的区别与联系【转+改】
数组 内存连续分配,长度大小固定,内置的最基础的数据结构之一.支持随机访问和随机存储. 该类型数据所占内存空间最小. Vector 是C++ STL中的一个容器.和数组类似,它拥有一段连续的内存空间, ...
- SAXReader解析xml文件demo
1. 加入jar包 2. 代码解析 package practice; import java.io.File; import java.util.List; import org.dom4j.Doc ...
- pydensecrf安装报错1、UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb6 in position 29: invalid start byte2、 LINK : fatal error LNK1158: 无法运行“rc.exe” error: command 'D:\\software\\vs2015\\VC\\BIN
pydensecrf安装报错 1.UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb6 in position 29: invalid st ...
- spring事务管理源码解析--加了@Transactional注解后Spring究竟为我们做了哪些事情?
大家都知道事务管理是基于AOP的,对AOP还不了解的请自行百度. 实现一个事务需要以下几步:1.获取数据库连接 2.执行数据库操作 3.如果2步骤发生异常就回滚,否则就提交 4.释放资源. 然后 ...
- destoon二次开发基础指南
代码首先包含common.inc.php文件 在common.inc.php文件中,首先定义常量. define('IN_DESTOON', true); define('IN_ADMIN', def ...
- jQuery 如何存储,获取和删除 Cookies
jQuery.cookie = function(name, value, options) { if (typeof value != 'undefined') { options = option ...
- C语言基础(20)-文件操作(fopen,getc,fclose)
一.文件操作 读文件的顺序: 1.先打开文件 2.读写文件 3.关闭文件 1.1 fopen FILE *fopen( const char *path, const char *mode ); 函数 ...
- javascript (function() { /* code */ })() 自执行函数
(function(){ function a(){ alert("a"); } })(); 自执行匿名函数: 常见格式:(function() { /* code */ })() ...