2016-01-06 5 views
14

Ho incontrato questo comportamento sciocco in modo rapido in cui lo scostamento forzato di un opzionale non si propaga.eccezione per lo scostamento rapido della forza non propagata

Dalla documentazione:

Cercando di utilizzare! per accedere a un valore opzionale inesistente si innesca un errore di runtime. Assicurati sempre che un optional contenga un valore diverso da zero prima di utilizzarlo! forzare a scartare il suo valore.

di riprodursi:

func foo(bar:String?) throws{ 
    print(bar!); 
} 

E

try foo(nil); 

questo non sembra logico o coerente a me e non riesco a trovare alcuna documentazione su questo argomento.

È questo in base alla progettazione?

+2

Non sono sicuro che lanciare un errore con 'throw' (che è ciò che causa la propagazione di errori all'interno di tale funzione) è la stessa cosa che accade quando si forza a scartare un' nil'. Penso di aver letto da qualche parte che è implementato come un 'assert()'. –

+0

Questo spiegherebbe, ma è terribile. Forse c'è un argomento per questo, ma in un linguaggio che supporta le eccezioni sembra incoerente. – Greg

+7

@ Greg: Nicolas ha ragione. Si noti che try/catch gestisce gli errori Swift * * (i valori conformi a 'ErrorType' che vengono lanciati). Questo è * completamente non correlato * agli errori di runtime o alle eccezioni. (La documentazione non menziona nemmeno la parola "eccezione" in relazione a throw/try/catch, solo "Gestione degli errori".) –

risposta

10

Dal documentation:

Gestione degli errori

La gestione degli errori è il processo di rispondere e il recupero da condizioni di errore nel programma. Swift fornisce il supporto di prima classe per lanciare, catturare, propagare e manipolare gli errori recuperabili in fase di runtime.

...

Rappresentazione e Generazione di errori

In Swift, errori sono rappresentati da valori di tipi conformi alle protocollo ErrorType. Questo protocollo vuoto indica che un tipo può essere utilizzato per la gestione degli errori.

(Nota: ErrorType è stato rinominato Error a Swift 3)

Quindi, con try/catch voi gestire errori Swift (valori di tipi che sono conformi al protocollo ErrorType), che sono throw n. Questo è completamente estraneo agli errori di runtime e alle eccezioni di runtime (e anche non correlato a NSException dalla libreria Foundation).

Nota che la documentazione Swift sulla gestione degli errori non ha nemmeno usare la parola "eccezione", con l'unica eccezione di (sottolineatura mia) a (!):

NOTA movimentazione

errore in Swift è simile alla gestione delle eccezioni in altre lingue , con l'uso delle parole chiave try, catch e throw.A differenza della gestione delle eccezioni in molte lingue, inclusa la correzione dell'errore C-Object in Swift non è richiesto lo svolgimento dello stack di chiamate, un processo che può essere molto costoso dal punto di vista computazionale. Pertanto, le prestazioni di un'istruzione di lancio sono paragonabili a quelle di un'istruzione di reso .

La srotolamento di opzionali che sono nil non fa throw un errore Swift (che potrebbe essere propagata) e non può essere trattato con try.

è necessario utilizzare le tecniche ben note come optional, concatenamento opzionale vincolante, controllando contro nil ecc

+0

Non ho mai provato ad usare il try per catturare lo unwrapping, parlo solo di ciò che si sta propagando. Ma tu rispondi bene. Un caso in cui mi sono imbattuto in questo sta usando SwiftyJSON e parsing json. Ho un'entità che contiene un'entità figlio che semplicemente gettere (propagare) il campo inesistente nella risposta JSON. Ora utilizzo inizializzatori facoltativi per ottenere la stessa cosa, ma ora ci sono altre 3 righe di codice: P – Greg

+0

@Greg: Bene, qualsiasi errore generato deve essere catturato da qualche parte. Ma ho cambiato la formulazione per abbinare meglio la tua domanda. –

5

questo esempio 'autoesplicativo' può aiutare a vedere la differenza tra sollevando un'eccezione di runtime e lancio un errore E conforme al protocollo ErrorType.

struct E: ErrorType{} 
func foo(bar:String?) throws { 
    if let error = bar where error == "error" { 
      throw E() 
    } 
    print(bar, "is valid parameter, but don't try to access bar.characters, it crash your code! (if bar == nil)") 
    // here is everything OK 
    let bar = bar! 
    // but here it crash!! 
    _ = bar.characters 
} 

do { 
    try foo("error") 
    // next line is not accessible here ... 
    try foo(nil) 
} catch { 
    print("\"error\" as parameter of foo() throws an ERROR!") 
} 
do { 
    try foo(nil) // fatal error: unexpectedly found nil while unwrapping an Optional value 
} catch { 

} 

esso stampa

"error" as parameter of foo() throws an ERROR! 
nil is valid parameter, but don't try to access bar.characters, it crash your code! (if bar == nil) 
fatal error: unexpectedly found nil while unwrapping an Optional value 

sollevando un'eccezione runtime è errore fatale nel codice.