2009-11-24 6 views
9

Próbuję wyświetlić UIAlertView w obsłudze wyjątków dla iPhone'a najwyższego poziomu. Funkcja obsługi wygląda następująco:Wyświetlanie alertu w wyjątku obsługi wyjątków najwyższego poziomu w telefonie iPhone

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

Widziałem podobny kod gdzie indziej (na przykład NSSetUncaughtExceptionHandler not catch all errors on iPhone).

Jeśli wykonam jeden krok w debugerze, widzę, że wywoływacz wyjątków jest wywoływany i widzę, że bieżący ekran jest przyciemniony, tak jakby wyświetlał alert przed nim, ale nic nie pojawia się. Poza debuggerem, aplikacja po prostu wychodzi natychmiast i wraca do ekranu głównego systemu.

To działa, jeśli pułapkę błąd w applicationDidFinishLaunching i wyświetlać alert przed powrotem. Zakładam, że widok alertu nigdy nie ma szansy na wyświetlenie w procedurze obsługi wyjątków, ponieważ aplikacja się kończy (w przeciwieństwie do siedzenia tam, nie robiąc nic, jeśli po prostu wyskoczę z aplikacjiDidFinishLaunching). Czy istnieje sposób, aby to zadziałało?

Odpowiedz

8

Nie wiem dokładnie, jak [alertView show] jest realizowany, ale mogę sobie wyobrazić to sprawia, że ​​pewne zmiany w hierarchii widoku, a następnie ustawia się, aby wyświetlić alert na następnym przejściu przez pętlę biegu (patrz w górę NSRunLoop).

Ale ponieważ aplikacja wkrótce się zakończy, sterowanie nie powróci do pętli uruchamiania, więc alarm nigdy nie zostanie wyświetlony. Dlatego widzisz, że ekran jest przyciemniony (alert UIWindow jest natychmiast dodawany przez show), ale alert nie pojawia się (zdarzyłoby się to w pętli uruchamiania).

Dołączenie [[NSRunLoop currentRunLoop] run] na końcu procedury obsługi wyjątku może spowodować wyświetlenie alertu.

Jeśli chcesz, aby aplikacja została zamknięta po zakończeniu alertu, prawdopodobnie możesz to zrobić, dzwoniąc pod numer runUntilDate: NSRunLoop, sprawdzając wartość flagi, aby sprawdzić, czy alert został jeszcze odrzucony. Jeśli tak, po prostu wyjdź z funkcji obsługi i już możesz iść. Oznacza to, że będziesz musiał ustawić obiekt delegata na alert, który ustawia tę flagę.

Jeśli chcesz, aby aplikacja nadal działała ... nie jestem tego pewien. Możesz po prostu pozwolić, aby pętla uruchamiania nadal działała poza obsługą wyjątku, ale mogą to być złe/dziwne efekty uboczne. Więc prawdopodobnie powinieneś pozwolić aplikacji odejść. Poza tym, jeśli jesteś pewien, że możesz wyjść z wyjątku, powinieneś go gdzieś złapać.

+0

"[[NSRunLoop currentRunLoop] Run]" załatwiło sprawę. Dzięki! –

+0

Dzięki, napisałem inne rozwiązanie do tego wątku w oparciu o twoją odpowiedź. –

+0

Czy na pewno trzeba wyświetlić komunikat o błędzie użytkownikowi? Być może najlepiej byłoby, gdyby w milczeniu poradzić sobie z tym wyjątkiem i nie musisz się martwić, że i tak rozwiązałeś ten problem. –

0

Powinieneś sprawdzić, czy kod został osiągnięty lub masz problem z wyświetlaniem.

NSLog wyjaśni to.

Jeśli nie osiągnął, trzeba zapobiec aplikacji zamknięcie, a może trzeba opóźnionego działania, aby wydostać się z tej sytuacji dla nadejścia połączenia:

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

Jeśli osiągnięcie go i kontekst wykonanie nie jest problem, ale po prostu nie widzisz alarmu, wtedy [alert show] może nie być na najwyższym poziomie w wyświetlaniu. W takim przypadku może być konieczne przekierowanie wiadomości przez showinview np. z actionsheet:

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

[actionSheet showInView:topDelegateWindow]; 
9

Dzięki stosom do benzado, uważam, że jest to świetny ogólny wyjątek obsługi najwyższego poziomu. Jestem początkującym, więc mam nadzieję, że jest zrobione poprawnie, ale to działa :)

W moim ... 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; 
} 

i moim ... appDelegate.h:

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

Wygląda dobrze. Osobiście utworzyłbym oddzielny obiekt, który miałby pełnić funkcję delegata alarmu. Ponieważ jesteśmy w trybie awaryjnym, warto odizolować się od reszty kodu aplikacji. Ale poza tym wygląda dobrze. – benzado

+0

można to uczynić ładniej prostszym w połączeniu z implementacją uialertview + blocks. W ten sposób (nie mój kod): https://github.com/MugunthKumar/UIKitCategoryDodatki –

Powiązane problemy