2009-07-13 12 views
8

Sto lavorando sul porting di una base di codice Java per Cocoa/Objective-C per l'uso su scrivania codice di Mac OS X. Il Java è sacco e sacco dei metodi con eccezioni controllate come:Quando si esegue il porting del codice Java su ObjC, qual è il modo migliore per rappresentare le eccezioni controllate?

double asNumber() throws FooException { 
    ... 
} 

cos'è il modo migliore per rappresentarli in Objective-C? Eccezioni o parametri di errore?

- (CGFloat)asNumber { 
    ... // possibly [FooException raise:format:]; 
} 

o

- (CGFloat)asNumberError:(NSError **)outError { 
    ... 
} 

ho la sensazione che fuori-errori sono in genere la soluzione migliore per Objective-C, ma come si può vedere ... un sacco di metodi come quello di cui sopra sarà essere piuttosto goffo. E ancora, ci sono lotti di questi.

Naturalmente tenere a mente che poiché questi sono controllati eccezioni in Java, ho bisogno di aggiungere sia @try blocchi o if (*outError) {...} controlli ovunque questi metodi vengono chiamati (sacco dei posti).

Ricordo che durante l'immissione dei blocchi @try era una volta costoso in Objective-C, è economico in 64-bit o SL o qualche altro nuovo env (non ricordo esattamente). Non sono affatto preoccupato per la compatibilità all'indietro, quindi sono sicuramente disposto a progettare solo per il nuovo hotness.

+1

per quelli che seguono a casa, ho deciso di andare con errori esterni e seguire consigli di NSScanner di Quinn. quindi questo particolare metodo sarebbe qualcosa di simile: '- (BOOL) getNumber: (CGFloat *) errore outNum: (NSError **) outErr;' –

+0

@olliej indica correttamente che i blocchi @try sono "a costo zero" nel runtime moderno (64-bit e iPhone), ma le eccezioni costano ancora quando le butti. Inoltre, se lo desideri, puoi usare 'double' al posto di' CGFloat'. Vai con qualunque sia la migliore pratica per l'ambiente in cui ti trovi e il codice con cui ti integrerai. –

risposta

16

Si consiglia di evitare eccezioni per le operazioni di analisi dei numeri da stringhe. In Objective-C, le eccezioni rappresentano l'errore del programmatore, non l'errore di input dell'utente o nemmeno i file non disponibili. (Parte della ragione è che la gestione delle eccezioni è sempre più costosa e complessa di una gestione più "normale" degli errori. Indipendentemente dal fatto che sia entering @try blocks is "zero cost" in 64-bit, è ancora lento ogni volta che un'eccezione viene effettivamente sollevata.) Naturalmente, è consentito utilizzare eccezioni come ti piace, ma non è il modo Cocoa, e ti troverai in contrasto con altri codici Objective-C. Le persone che usano il tuo codice saranno incredibilmente infastidite dal fatto che tu crei delle eccezioni in casi che dovrebbero solo causare un errore.

Da Apple's own docs:

"In many environments, use of exceptions is fairly commonplace. For example, you might throw an exception to signal that a routine could not execute normally—such as when a file is missing or data could not be parsed correctly. Exceptions are resource-intensive in Objective-C. You should not use exceptions for general flow-control, or simply to signify errors. Instead you should use the return value of a method or function to indicate that an error has occurred, and provide information about the problem in an error object."

Guardate come built-in classi Cocoa gestire gli errori di questo tipo. Ad esempio, NSString ha metodi come -floatValue che restituiscono 0 se non riesce.Una soluzione migliore per la tua situazione particolare potrebbe essere come NSScanner, ad esempio in -scanFloat:: accettare un puntatore al campo in cui deve essere archiviato il risultato e restituire YES o NO in base al successo dell'analisi.

A parte la convenzione Obejctive-C e le migliori pratiche, NSError è molto più robusto e flessibile di NSException e consente al chiamante di ignorare efficacemente il problema, se lo desidera. Suggerisco di leggere lo Error Handling Programming Guide For Cocoa. Nota: Se si accetta un parametro NSError**, si consiglia vivamente di progettare anche per consentire al client di passare NULL se non si desidera ricevere alcuna informazione di errore. Ogni classe Cocoa di cui sono a conoscenza fa questo per errori, incluso NSString.

Anche se il codice trasferito può sembrare completamente diverso dal codice Java, riconoscere che verrà utilizzato dal codice Objective-C, non dagli stessi client dell'equivalente Java. Sicuramente si abbinano agli idiomi della lingua. La porta non sarà un'immagine speculare del codice Java, ma sarà molto più corretta (per Objective-C) come risultato.

+0

thx per il tuo feedback Quinn –

+1

mi piace soprattutto il consiglio 'NSScanner' ... che ti aiuterà a ripulire un po 'i nomi dei metodi e renderli più naturali in ObjC. –

-1

Le eccezioni sono probabilmente l'approccio migliore, poiché l'ABI a 64 bit Obj-C (runtime) utilizza eccezioni a costo zero, in modo da ottenere un codice più pulito senza alcun costo reale. Ovviamente a 32-bit le vecchie eccezioni setjmp/longjmp sono ancora in uso e non interagiscono con C++, quindi se questo è un obiettivo allora si ha un problema.

+0

thx per il grande feedback oliver. e per la cronaca, no. Non mescolerò questo codice base con C++ in alcun modo. –

+0

-1 Mi dispiace, ma questo è un consiglio TERRIBILE per Objective-C. Non tutte le eccezioni sono "a costo zero", solo quelle che non si verificano mai effettivamente sono (proprio come i blocchi incontrastati durante la programmazione con la concorrenza). Nel momento in cui rilanci ("lancia") un'eccezione, paghi il prezzo. Affermare che il risultato è un "codice più pulito" è un'aringa rossa, perché sebbene il codice della libreria possa solo sollevare un'eccezione, ogni singolo client deve gestire l'eccezione usando @try e @catch. Il "modo Cocoa" consiste nell'usare errori e codici di ritorno per tali situazioni. Se si desidera che la porta sia un buon codice Objective-C, NON USARE ECCEZIONI. –

+1

@Quinn: le eccezioni del "costo zero" sono un termine ben compreso che significa specificamente costo zero se l'eccezione non viene generata.L'ABI Obj-C a 32 bit utilizza setjmp e longjmp per implementare le eccezioni, il che significa che @ try/@ catch ha un costo elevato se l'eccezione viene lanciata o meno. – olliej

3

Hai ragione che "gli errori di uscita sono generalmente la soluzione migliore per ObjC". Molto raramente troverai un'API in Cocoa che genera un'eccezione (a meno che tu non abbia soddisfatto le precondizioni per l'API, ma in tal caso, il comportamento non è definito per impostazione predefinita).

Se si prevede che questo codice vivi al di là di te e venga adottato da altri sviluppatori Cocoa, ti consigliamo di utilizzare gli errori. Io lavoro su un codice che è stato costruito da persone che non conoscono Cocoa e che hanno usato eccezioni in modo generoso, e sono una vera e propria pena lavorare intorno.

7

In Cocoa, le eccezioni devono essere utilizzate solo per "errori di programmazione"; la filosofia è lasciare che l'app li catturi, dare all'utente la possibilità di salvare ciò che stanno facendo e uscire. Per prima cosa, non tutti i framework o i percorsi di codice possono essere sicuri al 100%, quindi questo può essere l'unico corso sicuro di azione. Per gli errori che possono essere anticipati e recuperati da, è necessario utilizzare NSError, in genere tramite un parametro esterno.

+1

Quindi le eccezioni Objective-C sono simili a come viene definito l'errore in Java: non ci si aspetta che le gestirai, ma piuttosto si bloccheranno con grazia. –

2

Sono un grande fan dell'approccio out error che Objective-C utilizza. Devi gestire le eccezioni, ma puoi scegliere di ignorare gli errori se lo desideri. Tutto si adatta all'atteggiamento Objective-C che "il programmatore sa cosa stanno facendo". Rende anche Objective-C un linguaggio molto pulito, perché il tuo codice non è ingombrato da blocchi try-catch.

Detto questo, si potrebbe prendere in considerazione: Esistono scenari in cui le eccezioni vengono ignorate? Le eccezioni che lanci veramente sono la critica? Ti ritrovi a scrivere semplici blocchi catch che puliscono le variabili e proseguono? Mi sporgerei verso gli errori perché mi piace la sintassi e Objective-C riserva eccezioni solo per gli errori più critici.

+0

hrm, bene nel sorgente Java, queste sono * controllate * eccezioni, quindi con il design attuale, sì, devono assolutamente essere gestite. per quanto siano veramente critici, suppongo sia una domanda più dura. Forse non sono veramente critici, e l'autore originale stava approfittando di una bella funzionalità del linguaggio originale (Java). Dirò .... ho il massimo rispetto per l'autore originale. sicuramente conosce la sua roba (almeno in Java). –

+0

+1 Per essere sicuri, nessuna mancanza di rispetto è intesa all'autore originale. Quando scrivo in Java, seguo le convenzioni (sia della lingua che del mio team) e spesso getta eccezioni controllate in casi simili. È più una considerazione del contesto e ciò che si adatta meglio a un determinato contesto. È anche bello lasciare che il cliente decida quando è veramente fondamentale gestire un errore, piuttosto che dover sempre difendersi da una NumberFormatException, NullPointerException, ecc. –

2

Sembra simile a queste eccezioni controllate in modo più accurato mappare gli errori. Le eccezioni potrebbero comunque essere utilizzate, ma dovrebbero essere riservate a circostanze eccezionali.

Problemi correlati