Objective-C异常崩溃捕捉


<!–markdown–>#简述

用于在 app异常崩溃时能够捕捉错误信息,并通过保存本地或邮箱或http保存。

github:https://github.com/kaler/CrashKit
参考文章:http://www.cnblogs.com/alario/archive/2012/03/27/2419710.html ;
参考文章B:http://www.cocoachina.com/newbie/tutorial/2012/0829/4672.html ;
demo:http://pan.baidu.com/s/1kTiau8n。

github上的这个组件很棒,就是最后更新时间为 3 year ago…..
<p><!–more–></p>
所以为了让他可以正常运行花了我不少时间。

同时,顺便我又添加了一个 保存在本地(设备沙盒)的功能。
再顺便,又添加了一些新的崩溃信号,用于捕捉异常。

在查看源代码的时候,我发现了一个很好玩的函数 :signal()。

百度百科:
        sig是传递给它的唯一参数。执行了signal()调用后,进程只要接收到类型为sig的信号,不管其正在执行程序的哪一部分,就立即执行func()函数。当func()函数执行结束后,控制权返回进程被中断的那一点继续执行。

sgnal(信号,function());   注意,是接受到信号之后,不论你在干什么都会跑去先执行 function(),等这个function执行完成后,再返回原来的断点继续执行原来的代码。
signal(信号, SIG_DFL); 这是取消  sgnal(信号,function()); 设置之后再接收到 该信息,function()就不会再作出处理。

小细节:为什么要设置signal函数?
引用文章1:

言归正传。开发iOS应用,解决Crash问题始终是一个难题。Crash分为两种,一种是由EXC_BAD_ACCESS引起的,原因是访问了不属于本进程的内存地址,有可能是访问已被释放的内存;另一种是未被捕获的Objective-C异常(NSException),导致程序向自身发送了SIGABRT信号而崩溃。其实对于未捕获的Objective-C异常,我们是有办法将它记录下来的,如果日志记录得当,能够解决绝大部分崩溃的问题。这里对于UI线程与后台线程分别说明。

<h3>ios自带的</h3>

NSSetUncaughtExceptionHandler( handleRootException );
仅能捕捉后一种。 所以我们需要 signal 捕捉程序崩溃时的信息来捕捉第一种。
应该说,理论上仅仅只使用 signal 监视所有的异常信号的话就可以捕捉到所有的异常。

#下面是正题

<h3>一.使用方法</h3>

 1. 将  CrashController.h,CrahController.m,CrashLogger.h,CrashLogger.m文件添加到工程里
 2.在appDelegate 里实例化代码如下


  #ifdef DEBUG
    CrashController *crash=[CrashController sharedInstance];//1.实例化异常捕
    crash.delegate=self;//给异常捕捉设置事件委托,其实不加也没事=  - =主要是加了之后你可以在appdelegate里使用一个onCrash的事件方法,当程序崩溃的时候
//2.设置捕捉到异常信息之后,对信息的处理方式,只能设置一种,多次设置会被覆盖。
    //写到本地
    [crash sendCrashReportsToLocalXmlFile];
    //发送到邮箱
   /* [crash sendCrashReportsToEmail:@&#34;454872418@qq.com&#34;
     withViewController:self.window.rootViewController];
    */
    //发送到webservices 
    /*
     [crash sendCrashReportsToBugzScoutURL:@&#34;https://smartfulstudios.fogbugz.com/api.asp&#34;
     withUser:@&#34;.com&#34;
     password:@&#34;&#34;
     forProject:@&#34;Inbox&#34;
     withArea:@&#34;Misc&#34;];
     */
#endif 

使用方法就这么简单,用到的就只有三句代码。 其实,应该只要两句就够了。。
小细节:这里用到了单例哦,是一个很典型的单例使用教程。
小细节2:上面的#ifdebug宏,是为这段代码只有在debug的时候才会生效,因 为我还没有想好让这段代码只在测试人员 测试时生效呢
还是对普通用户也生效。
<h3>二、实例测试</h3>

上面的代码已经在程序里设置好了异常捕捉模块,下面我来写一段错误代码来测试一下代码。

NSArray * ary=[NSArray arrayWithObjects:@&#34;aadfadfadf&#34;, nil];
   DLog(@&#34;%@&#34;,[ary objectAtIndex:1]);

注:这代码是写在一个viewcontroller里的一个button里的,在appdeledate里的错误是不能被捕捉到的
定义了一个数组 ary, 然后去打印并不存在的 index 1。那么程序应该会返回一个 下标越界的 异常

运行程序 ,让他出错,程序闪退了。
这里我用的是直接把文件保存到 app沙盒里,所以需要itools 同步助手等工具,去查看 documents下面的文件。
文件在logerrr文件夹下面 = - =。
效果如下图所示。
psb.png
该xml 一共保存了 call Stack 调用栈
signal 异常信号,详细查看苹果 signal.h类,
signal name 信息名称,为了方便查看设置的对应 isgnal异常信号的名称
Title 见 callStack 第6行
jmExName 异常名称
jmExReason 异常原因

有 jmExName 和jmExReason 记录下来时优先看 这两个,但是这两个不是会100%会被记录下来的,
只有 NSSetUncaughtExceptionHandler( handleRootException ); 这一类的异常才能记录 jmExName 和jmExReason。

<h3>三、结果</h3>

通过 jmExNme 和 jmExReason可以很轻易的看出。。。 下标超了。再看callstack里。。。

第13行, 异常发生在 yltabsettingvewcontroller 类下面的 checkUpdate 方法里, 是不是很方便?

小细节:如果测试邮件的话
1.请连接网络
2.在邮箱里设置帐号
3.确认设备支寺发送邮件。