2011-12-13 12 views
6

Un mio amico ha scoperto un comportamento strano con NSDictionary e sono curioso di sapere perché succede. Si consideri il seguente codice:Perché sembra che questa chiamata all'Obiettivo C si blocchi?

NSDictionary *dict = [[NSDictionary alloc] init]; 

// Oops, we can't mutate an NSDictionary 
[dict setObject:[[NSNull alloc] init] forKey:@"test"]; 
NSLog(@"Set"); 

Il codice produce un avvertimento sulla compilation che " 'NSDictionary' potrebbe non rispondere a 'setObject: Forkey:'". Questo è tutto molto bello, e se lo si esegue in ogni caso, si otterrà questa uscita nella console:

- [__ NSCFDictionary setObject: Forkey:]: mutando metodo inviato oggetto immutabile

Ancora, esattamente quello che ti aspetteresti che accada. Tuttavia, a questo punto l'app non si blocca o termina a causa di un'eccezione non rilevata. Il setObject: forKey: il metodo semplicemente non ritorna mai e l'app sembra bloccarsi; il seguente NSLog non viene mai eseguito. Se provi a scavalcare o nel metodo usando GDB, il debug sembra terminare, ma senza alcun messaggio di errore esplicito. L'app continua a funzionare, ma il debugger non fornisce alcuna indicazione su dove nel codice l'esecuzione è "bloccata".

Cosa sta succedendo qui? Che cosa sta effettivamente facendo l'app in questo caso e perché non si blocca con una NSInternalInconsistencyException o qualcosa del genere?

Modifica: per coloro che hanno chiesto, sto eseguendo XCode 4.1 su OS X Lion (10.7.2), costruendo con "Apple LLVM compilatore 2.1". Sto utilizzando tutte le impostazioni predefinite ottenute con un nuovo progetto Cocoa in XCode 4. Ho riscontrato lo stesso comportamento non irreversibile indipendentemente dal fatto che esegua il debug del programma o semplicemente lo esegua. Il passaggio da Debug building a Release building non fa differenza. Posso anche localizzare manualmente il file .app in Finder e fare doppio clic su di esso per eseguirlo al di fuori di XCode, e ancora non si blocca.

+1

Provare a eseguirlo non sotto il debugger; Scommetto che si blocca duramente. Trovo che l'ambiente del debugger possa avere alcuni effetti imprevisti sull'ambiente di runtime, specialmente riguardo alle eccezioni e cosa succede quando le colpisci. –

+2

Quando viene lanciata l'eccezione, il controllo riprende con qualsiasi cattura l'eccezione, * non * la riga successiva dopo l'eccezione. Nell'esempio, il debugger o le viscere del runtime hanno "rilevato" l'eccezione. In ogni caso non ci si aspetterebbe che NSLog si verifichi dopo -setObject: forKey: ha generato un'eccezione. –

+0

@VincentGable: concordato, se il programma si è bloccato non sarei minimamente sorpreso che NSLog non è stato chiamato. Ciò che mi sorprende è che non si blocca né avanza alla riga successiva. Sembra che dovrebbe fare l'uno o l'altro. A coloro che mi hanno chiesto, ho aggiornato la domanda con alcuni dettagli aggiuntivi sull'ambiente in cui sto correndo. –

risposta

1

Le eccezioni non bloccano i programmi AppKit. NSApplication installa un gestore di eccezioni predefinito che rileva le eccezioni non presenti nel codice. Quindi torni indietro nel runloop come al solito.

Un sacco di app mostrano questo comportamento. È una causa comune di visualizzazioni/finestre vuote inspiegabili. Se si verifica un'eccezione prima che una vista riesca a completare il disegno, la vista sarà vuota, ma l'app non si arresterà in modo anomalo. Le eccezioni causano un arresto anomalo solo se si modifica deliberatamente il gestore delle eccezioni predefinito in modo anomalo.

+0

Grazie, questo in gran parte risponde al mio domanda. Una cosa su cui sono ancora confuso, però, è il motivo per cui non riesco a vedere l'applicazione tornare al ciclo degli eventi principale dopo che è stata rilevata l'eccezione. O si verifica in un thread diverso? Non sono così familiare con il funzionamento interno di AppKit. –

Problemi correlati