2009-11-24 1 views
9

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

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

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

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

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

ответ

8

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

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

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

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

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

+0

"[[NSRunLoop currentRunLoop] Run]" сделал трюк. Благодаря! –

+0

Спасибо, я опубликовал другое решение этой темы на основе вашего ответа. –

+0

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

0

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

NSLog's разъяснит это.

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

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

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

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

[actionSheet showInView:topDelegateWindow]; 
9

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

В моем ... appDelegate.м:

- (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); 
+1

Выглядит хорошо. Лично я создал бы отдельный объект, который будет служить делегатом предупреждения. Поскольку мы находимся в аварийном режиме, имеет смысл изолироваться от остальной части кода приложения. Но в остальном хорошо выглядит. – benzado

+0

это можно сделать красивее легко в сочетании с реализацией uialertview + блоков. Как это (не мой код): https://github.com/MugunthKumar/UIKitCategoryAdditions –