2013-08-08 1 views
2

내 앱을 계속 진행할 수 없어서 종료해야하는 상황이 너무 심하게 잘못되면 사용자에게 경고 상자를 표시 한 다음 확인 버튼을 탭하면 앱을 종료하고 싶습니다. . 충분히 간단하게 들리는가?iOS 앱의 치명적인 오류 처리기

하지만 여기에 문제가 있습니다. 제 치명적인 오류 처리기가 제 3 자 라이브러리 (해당 소스 코드가 없음)에 의해 호출됩니다. 초기화시 치명적인 오류 처리기에 대한 포인터를 제공하고 치명적인 오류가 발생하면 단순히 루틴을 호출하여 절대로 반환하지 않을 것으로 기대합니다. 반환하면 제 3 자 라이브러리에서 오류를 처리 한 것으로 가정하고 계속 진행할 것입니다 (데이터가 일관성없는 상태에 있기 때문에 데이터가 손상 될 수 있음). 오류 처리기 끝에있는 응용 프로그램을 종료 할 수는 있지만 (사용자가 예상 한대로) 문제가 무엇인지 알려주는 메시지를 사용자에게 표시 할 수 있기를 원합니다.

불행하게도, 난 그냥 할 경우 :

-(void)fatalErrorHandler:(NSString *)msg 
{ 
    // Log the error and shut down all the things that need 
    // to be shut down before we exit 
    // ... 

    // Show an alert to the user to tell them what went wrong 
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:msg delegate:self cancelButtonTitle:@"Close" otherButtonTitles:nil]; 
    [alert show]; 
} 


-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex 
{ 
    exit(-1); 
} 

fatalErrorHandler 잘 나는 오류를 처리했고 마치 아무 일도 없었던 것처럼 그것을 계속 것이다 제 3 자 라이브러리를 알려줍니다 [경고 표시, 후 반환 . 이것은 좋지 않다.

fatalErrorHandler에서 돌아 오지 않아야합니다. 이제까지. 그러나 주 스레드에 있기 때문에 fatalErrorHandler가 반환 될 때까지 UIAlertView가 표시되지 않습니다. 캐치 22.

치명적인 오류 처리기에서 돌아 오지 않고 사용자에게 경고를 표시하는 방법에 대한 아이디어가 있습니까?

답변

0

이 wesley6j의 대답은 나에게 아이디어를 주었다. 다음은 내가 생각해 낸 것입니다.

-(void)fatalErrorHandler:(NSString *)msg 
{ 
    // Pop up an alert to tell the user what went wrong. Since this error 
    // handler could be called from any thread, we have to make sure this happens 
    // on the main thread because it does UI stuff 
    [self performSelectorOnMainThread:@selector(showMessage:) withObject:msg waitUntilDone:YES]; 

    // Now, if we're NOT on the main thread, we can just sleep forever and never 
    // return from here. The error handler will exit the app after the user 
    // dismisses the alert box. 
    if (![NSThread isMainThread]) 
     Sleep(0x7fffffff); 
    else 
    { 
     // OTOH, if we ARE on the main thread, we have to get a bit creative. 
     // We don't ever want to return from here, because this is a fatal error 
     // handler and returning means the caller can continue on its way as if 
     // we "handled" the error, which we didn't. But since we're on the main 
     // thread, we can't sleep or exit because then the user will never see 
     // the alert box we popped up in showMessage. So we loop forever and 
     // keep calling the main run loop directly to let it do its processing 
     // and show the alert. This is what the main run loop does anyway, so 
     // in effect, we just become the main run loop. 
     for (;;) 
     { 
      [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate: [NSDate date]]; 
     } 
    } 
} 


-(void)showMessage:(NSString *)msg 
{    
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:msg delegate:self cancelButtonTitle:@"Close" otherButtonTitles:nil]; 
    [alert show]; 
    [alert release]; 
} 

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex 
{ 
    exit(-1); 
} 

이것은 완벽하게 작동하며 필요한 부분을 정확하게 처리합니다.

0

이것이 작동하는지는 잘 모르겠지만, 루프를 시동하려면 sleep 루프로 시작하는 것이 어떻습니까? 변수 이 YES (어쩌면 alertViewDelegate) 일 때 while이 종료됩니다.

+0

문제는 내가 주 스레드에 있는데, 잠시 동안 실행 루프가 실행되지 않게됩니다. –

+0

타사 라이브러리는 다른 스레드에서 fatalErrorHandler를 호출 할만큼 똑똑해야합니다. 그건 애도 야. – Vik

+0

또한 애플의이 코드는 흥미로울 수있다. void InstallSignalHandler() { // 신호가 애플리케이션을 종료하지 않는지 확인한다. 신호 (SIGHUP, SIG_IGN); dispatch_queue_t queue = dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_source_t source = dispatch_source_create (DISPATCH_SOURCE_TYPE_SIGNAL, SIGHUP, 0, queue); if (source) { dispatch_source_set_event_handler (소스,^{ MyProcessSIGHUP(); }); // 처리 신호 시작 dispatch_resume (source); } }' – Vik

0

쓴 내용에서 "fatalErrorHandler는 [경고 표시] 직후에 반환되며 타사 라이브러리에 오류를 처리했으며 아무런 문제가없는 것처럼 계속 진행됩니다."

실제로 필요한 것은 fatalErrorHandler 메서드가 호출 될 때 모든 것을 일시 중지하는 것입니다. 이를 위해 alertView를 표시하기 전에 모든 NSTimer, 대기중인 메소드 등을 중지 할 수 있습니다.

또는, fatalErrorHandler이있는 경우 스레드를 일시 정지 (오래 오래 시간) usleep 사용 후 다른 스레드를 통해 alertView 표시 할 수 있습니다. 좋아

+0

내가 할 수있는 모든 UI 요소가 주 스레드에서 발생해야하므로 UIAlertView를 다른 스레드에서 표시하지 않습니다. 그렇지 않으면 정의되지 않은 동작이 발생합니다. 하지만 나에게 아이디어를 줬어. –