2009-04-12 10 views
9

Considerate i seguenti/Obj-C frammenti di codice Cocoa:In quali circostanze @finally non è ridondante in Cocoa's try/catch/finally Exception Handling?

MyClass *obj; 
@try { 
    [obj doSomething]; 
} 
@catch (NSException * e) { 
    NSLog(@"Exception occurred: %@", [e description]); 
} 
@finally { 
    [obj cleanUp]; 
} 

e

MyClass *obj; 
@try { 
    [obj doSomething]; 
} 
@catch (NSException * e) { 
    NSLog(@"Exception occurred: %@", [e description]); 
} 
[obj cleanUp]; 

In quali circostanze il primo risultato frammento in [obj cleanUp] essendo chiamato, mentre il secondo no risultato in [obj cleanUp] viene chiamato? In altre parole, in quali circostanze è @finally non ridondante quando si utilizza Cocoa Exception Handling?

risposta

5

In tal caso, dove si sta schiacciando l'eccezione, nessuno. @finally viene utilizzato per ripulire quando non si rileva l'eccezione o la si ripresenta, in ogni caso lasciando la risposta di eccezione finale al codice chiamante. Poiché le eccezioni in Cocoa dovrebbero essere utilizzate solo per errori di programmazione e quindi si verificano raramente, questa è una cosa assolutamente da fare.

E 'anche la pena sottolineare un caso in cui si non si bisogno di usare @finally, che è quando si imposta la propria piscina autorelease. Quando il pool di autorelease "genitore" viene distrutto, anche quelli interni che non sono ancora stati ripuliti saranno anche. Se provi a ripulirlo da solo, devi promuovere l'eccezione stessa dal tuo pool di autorelease.

+1

FYI, ecco la documentazione di Apple che spiega come eseguire la gestione della memoria con @ try/@ catch/@ throw/@ infine gestione delle eccezioni: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ Eccezioni/Task/HandlingExceptions.html # // apple_ref/doc/uid/20000059-SW7 –

1

Quando:

  • Non stanno recuperando il tipo di eccezione che si è verificato
  • Hai preso l'eccezione, ma il codice nel blocco catch getta anche un'eccezione.
15

In questi scenari non c'è differenza perché l'eccezione è ingerita. Qui ci sono due scenari in cui ci è una differenza:

[obj Cleanup] si chiama:

MyClass *obj; 
@try { 
    [obj doSomething]; 
} 
@catch (NSException * e) { 
    @throw;  
} 
@finally { 
    [obj cleanUp]; // called when exception is caught 
} 

[obj cleanup] non si chiama:

MyClass *obj; 
@try { 
    [obj doSomething]; 
} 
@catch (NSException * e) { 
    @throw; 
} 
[obj cleanUp]; // not called when exception is caught 
0

Una questione di livello inferiore, perché stai facendo questo?

Il try/catch/finally approccio è ampiamente usato in Java, ma quasi mai utilizzato in Objective-C, e non è un approccio preferito - semplicemente non ne hai bisogno, come le biblioteche non generare eccezioni il modo in cui le chiamate di libreria Java sarebbe e se stai scrivendo le tue librerie non dovresti aspettarti che i chiamanti pensino naturalmente a cercare le eccezioni da catturare.

La convenzione più utilizzata e compresa è quella di un delegato che dispone di un callback del metodo di errore, o forse di notifiche per guasti più generali che è necessario passare attraverso più livelli di codice. Questo approccio potrebbe essere più ampiamente utilizzato nel mondo Java se esistesse un semplice sistema di notifica nel modo in cui Cocoa lo ha impostato.

L'approccio delegato ha la stessa proprietà di documentazione che dichiara un'eccezione in Java, sono solo approcci diversi ma generalmente è meglio usare un approccio più adatto alla lingua a meno che non ci sia un motivo molto convincente per fare diversamente.

+0

Attualmente sto lavorando con try/catch/finally poiché lo Scripting Bridge di Apple in OS X 10.5 fallisce regolarmente generando eccezioni. Se si utilizza Scripting Bridge, non è possibile evitare eccezioni. Concordo pienamente sul fatto che, per la maggior parte del codice Cocoa/Objective-C, le eccezioni non sono il modo migliore per gestire gli errori. –

7

È anche interessante notare che il codice a blocchi @finally verrà eseguito quando il controllo esce dal blocco @tryper qualsiasi motivo, anche via return o goto. Per esempio:

@try { 
    doStuff(); 
    if(bail){ 
     return; 
    } 
    doMoreStuff(); 
} 
@finally { 
    [obj cleanUp]; 
} 
[obj announceSuccess]; 

[obj cleanUp] eseguirà anche se bail è vero, ma non lo faranno [obj announceSuccess].

Problemi correlati