虽然大家都不愿意看到程序崩溃,但可能崩溃是每个应用必须面对的现实,既然崩溃已经发生,无法阻挡了,那我们就让它崩也崩得淡定点吧。
IOS SDK中提供了一个现成的函数 NSSetUncaughtExceptionHandler 用来做异常处理,但功能非常有限,而引起崩溃的大多数原因如:内存访问错误,重复释放等错误就无能为力了,因为这种错误它抛出的是Signal,所以必须要专门做Signal处理。在didFinishLaunchingWithOptions 中,加入
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Source code
signal ( SIGABRT, MySignalHandler ); signal ( SIGILL, MySignalHandler ); signal ( SIGSEGV, MySignalHandler ); signal ( SIGFPE, MySignalHandler ); signal (SIGBUS, MySignalHandler ); signal (SIGPIPE, MySignalHandler ); |
回调函数MySignalHandler的定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
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 ]; } |
这段代码将会在崩溃时弹出一个对话框,我们还可以让它显示出设备信息,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
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; } |
在程序中加入这些代码之后,基本上所有崩溃都能Hold住了。崩溃时将会显示出如下的对话框:
这样在崩溃时还能从容地弹出对话框,比起闪退来,用户也不会觉得那么不爽。然后在下次启动时还可以通过邮件来发送Crash文件到邮箱,这就看各个应用的需求了。