Отображение предупреждения в обработчике исключений верхнего уровня iPhone
-
21-09-2019 - |
Вопрос
Я пытаюсь отобразить 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];