Отображение предупреждения в обработчике исключений верхнего уровня iPhone

StackOverflow https://stackoverflow.com/questions/1787254

Вопрос

Я пытаюсь отобразить UIAlertView в обработчике исключений iPhone верхнего уровня.Функция обработчика выглядит следующим образом:

void applicationExceptionHandler(NSException *ex) {
  UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error"
                                                      message:[ex reason]
                                                      delegate:nil
                                             cancelButtonTitle:@"OK"
                                             otherButtonTitles:nil];
  [alertView show];
}

Я видел подобный код в другом месте (например, NSSetUncaughtExceptionHandler не улавливает все ошибки на iPhone).

Если я выполняю один шаг в отладчике, я вижу, что вызван обработчик исключений, и я вижу, что текущий экран тусклый, как будто он собирается отобразить предупреждение перед ним, но ничего не появляется.За пределами отладчика приложение просто немедленно завершает работу и возвращается на начальный экран системы.

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

Это было полезно?

Решение

Я не знаю точно, как [alertView show] реализован, но я предполагаю, что он вносит некоторые изменения в иерархию представлений, а затем настраивает себя на отображение предупреждения при следующем прохождении цикла выполнения (посмотрите вверх NSRunLoop).

Но, поскольку приложение вот-вот завершит работу, управление не возвращается в цикл выполнения, поэтому предупреждение никогда не отображается.Вот почему вы видите экран тусклым (UIWindow уровня оповещения немедленно добавляется show) но предупреждение не появляется (это произошло бы в цикле выполнения).

Если вы включаете [[NSRunLoop currentRunLoop] run] в конце вашего обработчика исключений может появиться предупреждение.

Если вы хотите, чтобы ваше приложение завершило работу после завершения оповещения, вы, вероятно, можете сделать это, вызвав NSRunLoop runUntilDate: в цикле while проверяется значение флага, чтобы увидеть, было ли предупреждение уже отклонено.Если это так, просто выйдите из функции обработчика, и все готово.Это означает, что вам нужно будет установить объект делегирования в оповещении, которое устанавливает этот флаг.

Если вы хотите, чтобы ваше приложение продолжало работать...там я не так уверен.Вы могли бы просто позволить циклу выполнения продолжать выполняться из обработчика исключений, но это может привести к плохим / странным побочным эффектам.Так что вам, вероятно, следует позволить приложению завершиться.Кроме того, если вы уверены, что сможете восстановиться после исключения, вы должны были где-то его перехватить.

Другие советы

Огромное спасибо benzado, вот что я считаю отличным универсальным обработчиком исключений верхнего уровня.Я новичок, так что, надеюсь, все сделано правильно, но это действительно работает :)

В моем ...AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{        
    [window makeKeyAndVisible];

    NSSetUncaughtExceptionHandler(&exceptionHandler);

    return YES;
}

BOOL exceptionAlertDismissed = FALSE;
void exceptionHandler(NSException *exception)
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"App Committed Suicide"
        message:@"Oh dear, that wasn't supposed to happen. You will have to restart the application... sorry!"
        delegate:[[UIApplication sharedApplication] delegate] cancelButtonTitle:nil otherButtonTitles:@"That's ok!", @"Erm, bye...", nil];
    [alert show];
    [alert release];

    while (exceptionAlertDismissed == FALSE)
    {
        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
    }
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    exceptionAlertDismissed = TRUE;
}

И в моем ...AppDelegate.h:

@interface ...appDelegate : NSObject <UIApplicationDelegate, UIAlertViewDelegate>
...
void exceptionHandler(NSException *exception);

Вы должны проверить, достигнут ли код или у вас просто проблема с отображением.

NSLog прояснит это.

Если это не достигнуто, вам необходимо предотвратить завершение работы приложения, и вам может потребоваться отложенное действие, чтобы выйти из этого контекста для вызова предупреждения:

[self performSelector: @selector(showAlert:) withObject:@"msg" afterDelay: 0.1];

Если вы достигаете этого, и контекст выполнения не является проблемой, но вы просто не видите предупреждение, то [alert show] может отображаться не на верхнем уровне.В таком случае вам может потребоваться перенаправить сообщение через showinview, напримерс таблицей действий:

topDelegate=[[UIApplication sharedApplication] delegate];
topDelegateWindow=[topDelegate.window.subviews objectAtIndex:0];

[actionSheet showInView:topDelegateWindow];
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top