您当前的位置: 首页 > 旅游

如何让IOS应用从容地崩溃

2018-11-06 09:27:21

如何让IOS应用从容地崩溃

如何让IOS应用从容地崩溃 |爪游控 首页多彩生活娱乐八卦汽车世界科技产业数码新品游戏动漫体坛风云军情解码社会万象健康养生 首页 / 游戏动漫 / 如何让IOS应用从容地崩溃 如何让IOS应用从容地崩溃 Posted on 2014年3月8日 by stanper in 游戏动漫 文/donglin注:鉴于多名友对文中代码提出的质疑,联系了作者,迅速给予更正并更新。感谢大家的监督与支持!虽然大家都不愿意看到程序崩溃,但可能崩溃是每个应用必须面对的现实,既然崩溃已经发生,无法阻挡了,那我们就让它崩也崩得淡定点吧。IOS SDK中提供了一个现成的函数 NSSetUncaughtExceptionHandler 用来做异常处理,但功能非常有限,而引起崩溃的大多数原因如:内存访问错误,重复释放等错误就无能为力了,因为这种错误它抛出的是Signal,所以必须要专门做Signal处理。首先定义一个UncaughtExceptionHandler类,.h头文件的代码如下:#import UIKit/UIKit.h @interface UncaughtExceptionHandler : NSObject{ BOOL dismissed;}@endvoid 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 libkern/OSAtomic.h #include execinfo.h 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); char **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] 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]) { 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 中加入这一句代码就行了:[self InstallUncaughtExceptionHandler];现在,基本上所有崩溃都能Hold住了。崩溃时将会显示出如下的对话框:这样在崩溃时还能从容地弹出对话框,比起闪退来,用户也不会觉得那么不爽。然后在下次启动时还可以通过邮件来发送Crash文件到邮箱,这就看各个应用的需求了。原文 触控科技博客 获取更多相关内容,请关注爪游控公众号:zhuayoukong 文章导航Previous Previous post: 手游和主机游戏研发应互相学习什么?下一条 Next post: 张柏芝、谢霆锋和王菲,怎么都能在一起! 本站CDN由UPYUN又拍云强力驱动. 关于我们 | 加入我们 | 联系我们 | 版权声明 © 爪游控 版权所有. 陕ICP备号-1 Top

膜结构车棚
水式模温机
四氟
推荐阅读
图文聚焦