2009-04-02 13 views
10

Sono uno sviluppatore Microsoft da molto tempo e sono nuovo nello sviluppo di iPhone utilizzando XCode. Quindi sto leggendo un libro e analizzando esempi che cercano di insegnarmi come scrivere un'applicazione per iPhone usando Objective-C. Tutto è andato bene finora, tuttavia, di tanto in tanto mi imbatto nel messaggio generico "objc_exception_throw" in fase di esecuzione. Quando ciò accade, la fonte di questa eccezione è molto difficile da trovare. Dopo alcune prove ed errori ho trovato la mia risposta. Uno dei parametri era errato.Eccezione di debug generata in Objective C e XCode

Come si può vedere di seguito, ho sbagliato a digitare il parametro 'otherButtonTitles' tralasciando il secondo pulsante 't' nel pulsante.

UIAlertView *alert = [[UIAlertView alloc] 
         initWithTitle:@"Date and Time Selected" 
         message:message 
         delegate:nil 
         cancelButtonTitle:@"Cancel" 
         otherButonTitles:nil]; 

Il motivo per cui ho impiegato del tempo per trovare è che il codice sia stato realizzato correttamente. Questo comportamento normale è per il compilatore Objective-C? Sono abituato ad avere la compilazione fallita nel compilatore .NET quando faccio un errore di sintassi comune come questo. C'è un settaggio del compilatore che posso modificare per fare fallire la costruzione quando faccio questi errori?

+1

Qualcuno con più di Rep dovrei modificare il titolo di questo in qualcosa come "Debugging and prevent 'objc_exception_throw'". –

risposta

25

In primo luogo, aprire ~/.gdbinit (che è il file chiamato .gdbinit nella vostra home directory - sì, inizia con un punto) e mettere questo in esso:

fb -[NSException raise] 
fb objc_exception_throw 
fb malloc_error_break 

Che ti inizializzare GDB con tre punti di interruzione di default quando si verificano, GDB interromperà l'applicazione e mostrerà la traccia dello stack. Questo è molto ben integrato con Xcode in modo da essere in grado di camminare bene attraverso il codice facendo clic su stack elementi di traccia non appena un'eccezione si verifica da qualche parte o un malloc fallisce.

Poi, aprire il pannello Get Info sul progetto (o selezionare il progetto (in alto elemento nel Groups & Files) e premi cmd-i), passare alla scheda Build e impostare di Base SDK-Device - iPhone OS [someversion] vostro progetto. Scorri fino in fondo e trova la sezione GCC 4.0 - Warnings. Là; attivare tutti gli avvertimenti con cui ti trovi a tuo agio, ma assicurati di attivare Treat Warnings as Errors (questo è l'equivalente di GCC_TREAT_WARNINGS_AS_ERRORS). Personalmente, l'ho impostato a questo:

GCC Warning Build Settings http://lhunath.lyndir.com/stuff/gcc_warnings.png

Ora dovrebbe essere sempre avvisi del compilatore per la maggior parte delle cose che si possono fare male in codice e il compilatore non permetterò che si esegue il codice fino a risolverli. Quando le cose superano il naso del compilatore, dovresti essere in grado di trovare facilmente il problema con la rottura di GDB in un punto comodo.

Si dovrebbe anche esaminare NSZombie*. Queste sono variabili di ambiente che sono molto utili per interrompere in anticipo l'allocazione di memoria o le situazioni di accesso errate. Per esempio; wih NSZombieEnabled non verrà rilasciato nulla; su dealloc verrà sovrascritto con _NSZombie e se dovessi provare ad accedere nuovamente a questa memoria dealloced (dereferenziare un puntatore dealloced) otterrai qualcosa su cui interrompere in GDB, invece che la chiamata passerà come di consueto, verrà emessa solo in modo casuale dati (che, ovviamente, non è quello che volevi). Per maggiori informazioni su questo, vedere http://www.cocoadev.com/index.pl?NSZombieEnabled.

+0

NOTA: Affinché la sezione "Avvisi di GCC 4.0" appaia nelle impostazioni (come mostrato sopra) è necessario che l'SDK di base e l'SDK attivo siano impostati sul dispositivo e non sul simulatore. – rtemp

+0

Inoltre, quando abiliti "Tratta avvertimenti come errori" vedrai comunque gli avvertimenti come prima ma otterrai 1 errore un po 'fuorviante "Comando /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.0 non riuscito con codice di uscita 1 ". Questo errore scompare quando tutti gli avvisi vengono cancellati. – rtemp

8

I parametri errati devono in genere risultare in "Avviso: tale oggetto non risponde al selettore x" in giallo sulla linea in questione. Credo che questo sia attivo per impostazione predefinita, in quanto non dovevo modificare le impostazioni del compilatore per vederle.

Inoltre, quando ho incontrato un'eccezione non rilevata, a volte è utile a cadere nella console gdb (dovrebbe venire quando si esegue la vostra applicazione) e digitare quanto segue per ottenere backtrace per tutte le discussioni:

taa bt

+0

"taa bt" è l'abbreviazione di "thread apply all backtrace" e stampa semplicemente un backtrace per tutti i thread –

1

Il motivo per cui non si tratta di un errore di compilazione, è perché è perfettamente valido inviare un messaggio non noto in fase di compilazione a qualsiasi oggetto (e qualsiasi oggetto può essere configurato per gestire i messaggi anche in modo dinamico). Tutte le chiamate di metodo sono in realtà messaggi inviati agli oggetti.

In generale, se si visualizzano avvertenze, è necessario indirizzarle, poiché nella maggior parte dei casi possono causare problemi (come si è visto). L'aspetto fuorviante è qui che se si compila un file una volta e ha solo avvertimenti, se si compilano altre classi senza apportare modifiche alla classe che ha avvertimenti, l'avviso non verrà mostrato nei messaggi del compilatore. Quindi di tanto in tanto potresti voler "pulire tutti i bersagli" e ricostruire di nuovo per assicurarti di non perdere nessun avvertimento.

2

Quello che hai fatto non è un errore in fase di compilazione, perché il runtime Objective-C verifica in fase di esecuzione se un oggetto può rispondere al messaggio che gli viene inviato.

vi consiglio di aggiungere questa impostazione al vostro obiettivo o progetto di costruzione:

GCC_TREAT_WARNINGS_AS_ERRORS = YES 
9

Utilizzare sempre l'impostazione -Werror GCC (GCC_TREAT_WARNINGS_AS_ERRORS = YES). Non dovresti mai avere avvertenze nel tuo codice e questo è un esempio in cui l'avviso è un errore critico.

Inoltre, se si ottiene un objc_exception_throw, passare alla console (Command-shift-R) e cercare il primo indirizzo di numero "basso".

2009-04-01 13:25:43.385 CrashExample[41720:20b] Stack: (
    2528013804, 
    2478503148, 
    2528036920, 
    2528053460, 
    2358032430, 
    11076, 
    11880, 
    816174880, 
    345098340, 
    145973440, 
    816174880, 
) 

In questo caso, sarebbe "11076". Quindi digitare nella console:

info line *11076 

Che vi dirà la riga nel codice in cui è stata generata l'eccezione.

+0

Questo è un ottimo consiglio - un'altra cosa da aggiungere è impostare un punto di interruzione globale su "objc_exception_throw", che si interromperà automaticamente quando il tuo codice fa qualcosa che genera un'eccezione. –

Problemi correlati