iOS 에서 프로그램 이상 Crash 우호 화 처리 상세 설명

머리말
이틀 전 면접 을 받 은 면접 관 은 온라인 앱 이 반 짝 이 는 것 을 피 하 는 방법 을 물 었 다.먼저 인 코딩 할 때 여러 가지 용 오 를 하 는 것 이 생각 났 지만 면접 관 이 원 하 는 답 은 아 닌 것 같 아 엉망 이 었 다.오늘 시간 이 있 으 면 정리 하 러 오 세 요.도움 이 됐 으 면 좋 겠 어 요.
구현 효 과 는 그림:

효과 구현:

사용법:
1.캡 처 한 CatchedHelper 폴 더 를 프로젝트 프로젝트 프로젝트 에 끌 어 다 놓 습 니 다.
2.AppDelegate.m 에서 다음 과 같은 방법 을 찾 아 코드 를 추가 합 니 다.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 // Override point for customization after application launch.
 
 [UncaughtExceptionHandler installUncaughtExceptionHandler:YES showAlert:YES];
 return YES;
}
이상 코드 는 약간 우호 적 인 crash 차단 처 리 를 실현 할 수 있 습 니 다.
코드 설명:
UncaughtExceptionHandler.h 주요 코드:

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface UncaughtExceptionHandler : NSObject

/*!
 *        
 *
 * @param install         
 * @param showAlert           alertView
 */
+ (void)installUncaughtExceptionHandler:(BOOL)install showAlert:(BOOL)showAlert;
@end
UncaughtExceptionHandler.m 파일 의 주요 코드 는 다음 과 같 습 니 다.
1.이상 신호 보 내기

/*
 *        
 *
 * @param install          
 * @param showAlert           alertView
 */
+ (void)installUncaughtExceptionHandler:(BOOL)install showAlert:(BOOL)showAlert {
  
  if (install && showAlert) {
    [[self alloc] alertView:showAlert];
  }
  
  NSSetUncaughtExceptionHandler(install ? HandleException : NULL);
  signal(SIGABRT, install ? SignalHandler : SIG_DFL);
  signal(SIGILL, install ? SignalHandler : SIG_DFL);
  signal(SIGSEGV, install ? SignalHandler : SIG_DFL);
  signal(SIGFPE, install ? SignalHandler : SIG_DFL);
  signal(SIGBUS, install ? SignalHandler : SIG_DFL);
  signal(SIGPIPE, install ? SignalHandler : SIG_DFL);
}
위 와 같은 signal 이 생 겼 을 때 우리 가 정의 한 signal Handler 를 호출 하여 이상 을 처리 합 니 다.
ps:NSSetUncaught ExceptionHandler 는 iOS SDK 에서 제공 하 는 기 존 함수 로 이상 을 포착 하 는 방법 으로 사용 하기에 편리 합 니 다.하지만 던 진 시그 널 을 잡 을 수 없어 시그 널 핸들 러 방법 을 정의 했다.
2.처리 이상

void HandleException(NSException *exception) {
  
  
  int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);
  //         
  if (exceptionCount > UncaughtExceptionMaximum) {
    return;
  }
  
  //      
  NSArray *callStack = [exception callStackSymbols];
  NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:[exception userInfo]];
  [userInfo setObject:callStack forKey:UncaughtExceptionHandlerAddressesKey];
  
  //     ,       , withObject          
  [[[UncaughtExceptionHandler alloc] init]
   performSelectorOnMainThread:@selector(handleException:)
   withObject:
   [NSException exceptionWithName:[exception name]
               reason:[exception reason]
              userInfo:userInfo]
   waitUntilDone:YES];
}
이 방법 은 NSSetUncaughtExceptionHandler 의 처리 에 대응 하 는 것 입 니 다.이 함수 에 방법 이 연결 되 어 있 으 면 해당 오류 가 발생 했 을 때 이 함 수 를 자동 으로 호출 하고 호출 할 때 exception 인자 가 들 어 옵 니 다.이상 을 가 져 오 면 캡 처 된 이상 을 최종 호출 처리 한 handle Exception 함수 에 전달 합 니 다.
3.캡 처 할 수 없 는 signal 처리

//  signal  
void SignalHandler(int signal) {
  
  int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);
  //         
  if (exceptionCount > UncaughtExceptionMaximum) {
    return;
  }
  
  NSString* description = nil;
  switch (signal) {
    case SIGABRT:
      description = [NSString stringWithFormat:@"Signal SIGABRT was raised!
"]; break; case SIGILL: description = [NSString stringWithFormat:@"Signal SIGILL was raised!
"]; break; case SIGSEGV: description = [NSString stringWithFormat:@"Signal SIGSEGV was raised!
"]; break; case SIGFPE: description = [NSString stringWithFormat:@"Signal SIGFPE was raised!
"]; break; case SIGBUS: description = [NSString stringWithFormat:@"Signal SIGBUS was raised!
"]; break; case SIGPIPE: description = [NSString stringWithFormat:@"Signal SIGPIPE was raised!
"]; break; default: description = [NSString stringWithFormat:@"Signal %d was raised!",signal]; } NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; NSArray *callStack = [UncaughtExceptionHandler backtrace]; [userInfo setObject:callStack forKey:UncaughtExceptionHandlerAddressesKey]; [userInfo setObject:[NSNumber numberWithInt:signal] forKey:UncaughtExceptionHandlerSignalKey]; // , , withObject [[[UncaughtExceptionHandler alloc] init] performSelectorOnMainThread:@selector(handleException:) withObject: [NSException exceptionWithName:UncaughtExceptionHandlerSignalExceptionName reason: description userInfo: userInfo] waitUntilDone:YES]; }
이상 의 방법 은 캡 처 되 지 않 은 signal 신 호 를 처리 하여 일반적인 이상 유형 을 보 여 주 는 것 입 니 다.
4.스 택 호출

//      
+ (NSArray *)backtrace {
  
  //    
  void* callstack[128];
  //backtrace             ,           callstack 
  //128       buffer        void*  
  //             
  int frames = backtrace(callstack, 128);
  //backtrace_symbols  backtrace                 
  //              
  //             callstack           ,     、    、      
  char **strs = backtrace_symbols(callstack, frames);
  
  int i;
  NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];
  for (i = 0; i < frames; i++) {
    
    [backtrace addObject:[NSString stringWithUTF8String:strs[i]]];
  }
  free(strs);
  
  return backtrace;
}
backtrace 는 Linux 에서 함수 호출 스 택 과 위치 추적 세그먼트 의 오 류 를 추적 하 는 함수 입 니 다.
5.UIAlerView 를 사용 하여 우호 화 알림

- (void)handleException:(NSException *)exception {
  
  [self validateAndSaveCriticalApplicationData:exception];
  
  if (!showAlertView) {
    return;
  }
  
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
  UIAlertView *alert =
  [[UIAlertView alloc]
   initWithTitle:@"   "
   message:[NSString stringWithFormat:@"         ,            .
"] delegate:self cancelButtonTitle:@" " otherButtonTitles:@" ", nil]; [alert show]; #pragma clang diagnostic pop CFRunLoopRef runLoop = CFRunLoopGetCurrent(); CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop); while (!self.dismissed) { // for (NSString *mode in (__bridge NSArray *)allModes) { // Mode 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]; } }
여기에 서 는 서버 업로드 등 자신의 crash 수집 작업 을 할 수 있 습 니 다.
원본 코드 다운로드
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

좋은 웹페이지 즐겨찾기