2013-08-08 4 views
2

Когда что-то так ужасно ошибочно, что мое приложение не может продолжить и ему нужно выйти, я хочу открыть окно предупреждения пользователю, а затем закрыть приложение, когда они нажмут кнопку OK , Звучит достаточно просто, не так ли?Неустранимая обработчик ошибок в приложении iOS

Но вот в чем проблема: мой фатальный обработчик ошибок вызывается сторонней библиотекой (у меня нет исходного кода). Я даю им указатель на мой фатальный обработчик ошибок при инициализации, и когда они сталкиваются с фатальной ошибкой, они просто называют эту процедуру и ожидают, что она никогда не вернется. Если он вернется, сторонняя библиотека предположит, что я обработал ошибку, и она будет продолжаться на своем пути (возможно, искажая данные, потому что вещи сейчас находятся в противоречивом состоянии). Я мог бы просто выйти из приложения в конце моего обработчика ошибок (это то, что они ожидают), но я хочу сначала показать сообщение пользователю, чтобы сообщить им, в чем проблема.

К сожалению, если я просто делаю:

-(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. Когда-либо. Но поскольку я нахожусь в основном потоке, UIAlertView не появится, пока fatalErrorHandler не вернется. Уловка-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

Я не знаю, будет ли это работать, но как насчет запуска петли while с sleep в ее корпусе, скажем, на 1 секунду каждого цикла? Время будет выходить, когда переменная Bool была бы установлена ​​на YES, возможно, с alertViewDelegate.

+0

Проблема в том, что я нахожусь в основном потоке, и while будет поддерживать выполнение цикла выполнения. –

+0

Сторонняя библиотека должна быть достаточно умна, чтобы вызвать ваш fatalErrorHandler в другом потоке. Жаль – Vik

+0

Также этот код от Apple может быть интересным '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 (источник); } } ' – Vik

0

Из того, что вы написали, «fatalErrorHandler возвращается сразу после [предупреждения], которое сообщает библиотеке третьей стороны, что я обработал ошибку, и она будет продолжаться, как будто ничего не произошло».

Я думаю, что вам действительно нужно приостановить все, когда вызывается метод fatalErrorHandler. Для этого вы можете остановить все методы NSTimer, очереди и т. Д. Перед отображением alertView.

В качестве альтернативы, вы можете отобразить alertView с помощью другого потока, а затем использовать USleep (очень долго), чтобы приостановить нить, где fatalErrorHandler в.

+0

я могу 't отобразить UIAlertView из другого потока, потому что все элементы пользовательского интерфейса должны произойти в основном потоке (иначе это приведет к неопределенному поведению). Но ты дал мне идею ... –

Смежные вопросы