自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何讓iOS應(yīng)用從容地崩潰

移動開發(fā) iOS
我知道程序崩潰是大家都不愿意見到的問題,但是既然崩潰已經(jīng)發(fā)生,無法阻擋了,那我們就讓它崩也崩得淡定點吧。

雖然大家都不愿意看到程序崩潰,但可能崩潰是每個應(yīng)用必須面對的現(xiàn)實,既然崩潰已經(jīng)發(fā)生,無法阻擋了,那我們就讓它崩也崩得淡定點吧。

iOS SDK中提供了一個現(xiàn)成的函數(shù) NSSetUncaughtExceptionHandler 用來做異常處理,但功能非常有限,而引起崩潰的大多數(shù)原因如:內(nèi)存訪問錯誤,重復(fù)釋放等錯誤就無能為力了,因為這種錯誤它拋出的是Signal,所以必須 要專門做Signal處理。首先定義一個UncaughtExceptionHandler類,.h頭文件的代碼如下:

  1. #import <UIKit/UIKit.h> 
  2. @interface UncaughtExceptionHandler : NSObject 
  3. BOOL dismissed; 
  4. @end 
  5. void InstallUncaughtExceptionHandler(); 
  6. 然后在.mm文件實現(xiàn)InstallUncaughtExceptionHandler(),如下: 
  7. void InstallUncaughtExceptionHandler() 
  8. signal(SIGABRT, MySignalHandler); 
  9. signal(SIGILL, MySignalHandler); 
  10. signal(SIGSEGV, MySignalHandler); 
  11. signal(SIGFPE, MySignalHandler); 
  12. signal(SIGBUS, MySignalHandler); 
  13. signal(SIGPIPE, MySignalHandler); 

這樣,當應(yīng)用發(fā)生錯誤而產(chǎn)生上述Signal后,就將會進入我們自定義的回調(diào)函數(shù)MySignalHandler。為了得到崩潰時的現(xiàn)場信息,還可以加入一些獲取CallTrace及設(shè)備信息的代碼,.mm文件的完整代碼如下:

  1. #import "UncaughtExceptionHandler.h" 
  2. #include <libkern/OSAtomic.h> 
  3. #include <execinfo.h> 
  4. NSString * const UncaughtExceptionHandlerSignalExceptionName = @"UncaughtExceptionHandlerSignalExceptionName"
  5. NSString * const UncaughtExceptionHandlerSignalKey = @"UncaughtExceptionHandlerSignalKey"
  6. NSString * const UncaughtExceptionHandlerAddressesKey = @"UncaughtExceptionHandlerAddressesKey"
  7. volatile int32_t UncaughtExceptionCount = 0; 
  8. const int32_t UncaughtExceptionMaximum = 10; 
  9. const NSInteger UncaughtExceptionHandlerSkipAddressCount = 4; 
  10. const NSInteger UncaughtExceptionHandlerReportAddressCount = 5; 
  11. @implementation UncaughtExceptionHandler 
  12. + (NSArray *)backtrace 
  13.         void* callstack[128]; 
  14. int frames = backtrace(callstack, 128); 
  15. char **strs = backtrace_symbols(callstack, frames);   
  16. int i; 
  17. NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames]; 
  18. for ( 
  19. i = UncaughtExceptionHandlerSkipAddressCount; 
  20. i < UncaughtExceptionHandlerSkipAddressCount + 
  21. UncaughtExceptionHandlerReportAddressCount; 
  22. i++) 
  23. [backtrace addObject:[NSString stringWithUTF8String:strs[i]]]; 
  24. free(strs);   
  25. return backtrace; 
  26. - (void)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex 
  27. if (anIndex == 0) 
  28. dismissed = YES; 
  29. - (void)handleException:(NSException *)exception 
  30. UIAlertView *alert = 
  31. [[[UIAlertView alloc] 
  32. initWithTitle:NSLocalizedString(@"Unhandled exception", nil) 
  33. message:[NSString stringWithFormat:NSLocalizedString( 
  34. @"You can try to continue but the application may be unstable.\n" 
  35. @"%@\n%@", nil), 
  36. [exception reason], 
  37. [[exception userInfo] objectForKey:UncaughtExceptionHandlerAddressesKey]] 
  38. delegate:self 
  39. cancelButtonTitle:NSLocalizedString(@"Quit", nil) 
  40. otherButtonTitles:NSLocalizedString(@"Continue", nil), nil] 
  41. autorelease]; 
  42. [alert show];    
  43. CFRunLoopRef runLoop = CFRunLoopGetCurrent(); 
  44. CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);    
  45. while (!dismissed) 
  46. for (NSString *mode in (NSArray *)allModes) 
  47. CFRunLoopRunInMode((CFStringRef)mode, 0.001, false); 
  48. }    
  49. CFRelease(allModes); 
  50. NSSetUncaughtExceptionHandler(NULL); 
  51. signal(SIGABRT, SIG_DFL); 
  52. signal(SIGILL, SIG_DFL); 
  53. signal(SIGSEGV, SIG_DFL); 
  54. signal(SIGFPE, SIG_DFL); 
  55. signal(SIGBUS, SIG_DFL); 
  56. signal(SIGPIPE, SIG_DFL);    
  57. if ([[exception name] isEqual:UncaughtExceptionHandlerSignalExceptionName]) 
  58. kill(getpid(), [[[exception userInfo] objectForKey:UncaughtExceptionHandlerSignalKey] intValue]); 
  59. else 
  60. [exception raise]; 
  61. @end 
  62. NSString* getAppInfo() 
  63.     NSString *appInfo = [NSString stringWithFormat:@"App : %@ %@(%@)\nDevice : %@\nOS Version : %@ %@\nUDID : %@\n"
  64.                           [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"], 
  65.                           [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"], 
  66.                           [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"], 
  67.                           [UIDevice currentDevice].model, 
  68.                           [UIDevice currentDevice].systemName, 
  69.                           [UIDevice currentDevice].systemVersion, 
  70.                           [UIDevice currentDevice].uniqueIdentifier]; 
  71.     NSLog(@"Crash!!!! %@", appInfo); 
  72.     return appInfo; 
  73. void MySignalHandler(int signal) 
  74. int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount); 
  75. if (exceptionCount > UncaughtExceptionMaximum) 
  76. return
  77. NSMutableDictionary *userInfo = 
  78. [NSMutableDictionary 
  79. dictionaryWithObject:[NSNumber numberWithInt:signal] 
  80. forKey:UncaughtExceptionHandlerSignalKey]; 
  81. NSArray *callStack = [UncaughtExceptionHandler backtrace]; 
  82. [userInfo 
  83. setObject:callStack 
  84. forKey:UncaughtExceptionHandlerAddressesKey];    
  85. [[[[UncaughtExceptionHandler alloc] init] autorelease] 
  86. performSelectorOnMainThread:@selector(handleException:) 
  87. withObject: 
  88. [NSException 
  89. exceptionWithName:UncaughtExceptionHandlerSignalExceptionName 
  90. reason: 
  91. [NSString stringWithFormat: 
  92. NSLocalizedString(@"Signal %d was raised.\n" 
  93.                                           @"%@", nil), 
  94. signal, getAppInfo()] 
  95. userInfo: 
  96. [NSDictionary 
  97. dictionaryWithObject:[NSNumber numberWithInt:signal] 
  98. forKey:UncaughtExceptionHandlerSignalKey]] 
  99. waitUntilDone:YES]; 
  100. void InstallUncaughtExceptionHandler() 
  101. signal(SIGABRT, MySignalHandler); 
  102. signal(SIGILL, MySignalHandler); 
  103. signal(SIGSEGV, MySignalHandler); 
  104. signal(SIGFPE, MySignalHandler); 
  105. signal(SIGBUS, MySignalHandler); 
  106. signal(SIGPIPE, MySignalHandler); 

在應(yīng)用自身的 didFinishLaunchingWithOptions 前,加入一個函數(shù):

  1. - (void)installUncaughtExceptionHandler 
  2. InstallUncaughtExceptionHandler(); 

最后,在 didFinishLaunchingWithOptions 中加入這一句代碼就行了:

 

  1. [self InstallUncaughtExceptionHandler]; 

現(xiàn)在,基本上所有崩潰都能Hold住了。崩潰時將會顯示出如下的對話框:

這樣在崩潰時還能從容地彈出對話框,比起閃退來,用戶也不會覺得那么不爽。然后在下次啟動時還可以通過郵件來發(fā)送Crash文件到郵箱,這就看各個應(yīng)用的需求了。

責任編輯:閆佳明 來源: cocoachina
相關(guān)推薦

2015-04-08 09:26:21

IT管理云計算基礎(chǔ)設(shè)施數(shù)據(jù)存儲

2020-07-08 08:22:08

FlutterSVGPNG

2019-08-28 07:28:13

React應(yīng)用程序代碼

2021-01-18 13:17:04

鴻蒙HarmonyOSAPP

2020-11-06 08:13:03

服務(wù)器Nodejs客戶端

2021-01-28 14:53:19

PHP編碼開發(fā)

2015-12-03 14:33:35

2021-10-28 06:17:46

架構(gòu)設(shè)計組件

2009-11-20 11:52:10

2018-06-20 11:00:06

云應(yīng)用開發(fā)PaaS

2016-02-29 10:01:59

iosbug合理

2017-11-13 06:35:47

混合云應(yīng)用程序DevOps

2022-07-11 14:53:37

微服務(wù)容器IT

2015-02-26 09:19:00

2022-05-11 10:58:11

MetricKitiOS13系統(tǒng)崩潰診斷

2015-06-01 10:48:00

虛擬機云計算云就緒

2014-09-22 15:14:04

2017-04-28 09:04:32

移動應(yīng)用開發(fā)反饋

2022-07-13 13:29:56

微服務(wù)容器開發(fā)

2024-03-25 13:59:20

機器學(xué)習(xí)工業(yè)應(yīng)用
點贊
收藏

51CTO技術(shù)棧公眾號