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
@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