2009-11-24 7 views
9

Sto tentando di visualizzare un UIAlertView in un gestore di eccezioni di iPhone di livello superiore. La funzione di gestione è simile al seguente:Visualizzazione di un avviso in un gestore di eccezioni di livello superiore di iPhone

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

ho visto un codice simile altrove (per esempio, NSSetUncaughtExceptionHandler not catch all errors on iPhone).

Se eseguo il single-step nel debugger, posso vedere che il gestore di eccezioni è chiamato, e posso vedere lo schermo corrente debole come se stesse per visualizzare l'avviso di fronte ad esso, ma non appare nulla. Al di fuori del debugger, l'app si chiude immediatamente e torna alla schermata principale del sistema.

funziona se io trappola un errore nel applicationDidFinishLaunching e visualizzare un avviso prima di tornare lì. Presumo che la vista di avviso non abbia mai la possibilità di essere visualizzata nel gestore delle eccezioni perché l'app sta terminando (al contrario di stare lì senza fare nulla se non faccio altro che scaricare applicationDidFinishLaunching). C'è un modo per farlo funzionare?

risposta

8

non so esattamente come [alertView show] viene realizzato, ma immagino che apporta alcune modifiche alla gerarchia vista e poi si pone per visualizzare l'avviso sul prossimo passaggio attraverso il ciclo di esecuzione (vedi su NSRunLoop).

Ma, dal momento che l'applicazione è in procinto di uscire, il controllo non restituisce al loop corsa, in modo da l'allarme non viene mai visualizzato. Questo è il motivo per cui si vede la luminosità dello schermo (il livello di avviso UIWindow viene immediatamente aggiunto da show) ma l'avviso non appare (ciò accadrebbe nel ciclo di esecuzione).

Se si include [[NSRunLoop currentRunLoop] run] alla fine del gestore di eccezioni, è possibile che venga visualizzato l'avviso.

Se si desidera chiudere l'app una volta che l'avviso è terminato, è possibile farlo chiamando NSRunLoop's runUntilDate: in un ciclo while, controllando il valore di un flag per vedere se l'avviso è stato ancora rimosso. Se lo è, basta uscire dalla funzione di gestore e sei a posto. Ciò significa che dovrai impostare un oggetto delegato sull'avviso che lo imposta.

Se vuoi che la tua app continui a funzionare ... non ne sono così sicuro. Si può semplicemente lasciare che il ciclo di esecuzione continui a scappare dal gestore delle eccezioni, ma potrebbero esserci effetti collaterali negativi/strani. Quindi probabilmente dovresti lasciare che l'app si chiuda. Inoltre, se sei sicuro di poter recuperare dall'eccezione, dovresti averlo catturato da qualche parte.

+0

"[run [NSRunLoop currentRunLoop]]" ha fatto il trucco. Grazie! –

+0

Grazie, ho pubblicato un'altra soluzione a questo thread in base alla risposta. –

+0

Hai davvero bisogno di mostrare il messaggio di errore all'utente? Forse sarebbe meglio se tu potessi gestire silenziosamente l'eccezione e non dovresti preoccuparti di risolvere comunque questo problema. –

0

Verificare se il codice è stato raggiunto o se si è verificato un problema di visualizzazione.

NSLog's chiarirà che.

Se non raggiunta, è necessario per impedire l'arresto app, e potrebbe essere necessario un azione ritardata per uscire da tale contesto per la chiamata di allarme:

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

Se si stanno raggiungendo e contesto di esecuzione non è un problema, ma semplicemente non vedi l'avviso, quindi [lo stato di allerta] potrebbe non essere il primo livello in mostra. In tal caso, potrebbe essere necessario reindirizzare il messaggio tramite showinview, ad es. con actionsheet:

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

[actionSheet showInView:topDelegateWindow]; 
9

Grazie cumuli di benzado, ecco quello che penso è un grande gestore di eccezioni di primo livello generico. Sono un principiante così si spera è fatto correttamente, ma funziona :)

Nel mio ... 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; 
} 

E nella mia ... appDelegate.h:

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

Sembra buono. Personalmente, creerei un oggetto separato per fungere da delegato dell'avviso. Dato che siamo in modalità disastrata, ha senso essere isolati dal resto del codice dell'app. Ma per il resto, sembra buono. – benzado

+0

questo può essere reso più carino facilmente se combinato con un'implementazione di uialertview + blocchi. Come questo (non il mio codice): https://github.com/MugunthKumar/UIKitCategoryAdditions –