Gestione degli errori in Swift-Language


190

Non ho letto troppo in Swift ma una cosa che ho notato è che non ci sono eccezioni. Quindi, come fanno a gestire gli errori in Swift? Qualcuno ha trovato qualcosa legato alla gestione degli errori?


1
Ho trovato messaggi di errore proprio come con Obj-C: o
Arbitur

13
@Arbitur nel buon vecchio modo segreto?
peko,

Ho creato un NSTimer in Swift e quando ho scritto male la funzione si è arrestato in modo anomalo e mi ha dato un errore dicendo che non riusciva a trovare il metodo :)
Arbitur

3
Puoi aggiungere il supporto try-catch per Swift seguendo le istruzioni in questo articolo: medium.com/@_willfalcon/adding-try-catch-to-swift-71ab27bcb5b8
William Falcon,

@peko Come gestisci un segfault in Swift? Non credo sia possibile fin d'ora, il che purtroppo rende irrecuperabili alcuni errori
Orlin Georgiev,

Risposte:


148

Swift 2 e 3

Le cose sono cambiate un po 'in Swift 2, poiché esiste un nuovo meccanismo di gestione degli errori, che è in qualche modo più simile alle eccezioni ma diverso nei dettagli.

1. Indicazione della possibilità di errore

Se la funzione / metodo desidera indicare che potrebbe generare un errore, dovrebbe contenere una throwsparola chiave come questa

func summonDefaultDragon() throws -> Dragon

Nota: non esiste una specifica per il tipo di errore che la funzione può effettivamente generare. Questa dichiarazione afferma semplicemente che la funzione può generare un'istanza di qualsiasi tipo che implementa ErrorType o che non sta eseguendo affatto.

2. Richiamare la funzione che potrebbe generare errori

Per invocare la funzione è necessario utilizzare la parola chiave try, in questo modo

try summonDefaultDragon()

questa linea dovrebbe normalmente essere presente blocco di cattura come questo

do {
    let dragon = try summonDefaultDragon() 
} catch DragonError.dragonIsMissing {
    // Some specific-case error-handling
} catch DragonError.notEnoughMana(let manaRequired) {
    // Other specific-case error-handlng
} catch {
    // Catch all error-handling
}

Nota: la clausola catch utilizza tutte le potenti funzionalità di corrispondenza del modello Swift in modo da essere molto flessibili qui.

Puoi decidere di propagare l'errore, se stai chiamando una funzione di lancio da una funzione che è essa stessa contrassegnata con la throwsparola chiave:

func fulfill(quest: Quest) throws {
    let dragon = try summonDefaultDragon()
    quest.ride(dragon)
} 

In alternativa, puoi chiamare la funzione di lancio usando try?:

let dragonOrNil = try? summonDefaultDragon()

In questo modo si ottiene il valore restituito o zero, se si è verificato un errore. In questo modo non si ottiene l'oggetto errore.

Ciò significa che puoi anche combinare try?con dichiarazioni utili come:

if let dragon = try? summonDefaultDragon()

o

guard let dragon = try? summonDefaultDragon() else { ... }

Infine, puoi decidere di sapere che l'errore non si verificherà effettivamente (ad es. Perché hai già verificato i prerequisiti) e utilizzare la try!parola chiave:

let dragon = try! summonDefaultDragon()

Se la funzione genera effettivamente un errore, verrà visualizzato un errore di runtime nell'applicazione e l'applicazione verrà chiusa.

3. Lancio di un errore

Per generare un errore, utilizzare la parola chiave throw in questo modo

throw DragonError.dragonIsMissing

Puoi lanciare qualsiasi cosa conforme al ErrorTypeprotocollo. Per i principianti è NSErrorconforme a questo protocollo ma probabilmente ti piacerebbe andare con enum-based ErrorTypeche ti consente di raggruppare più errori correlati, potenzialmente con ulteriori pezzi di dati, come questo

enum DragonError: ErrorType {
    case dragonIsMissing
    case notEnoughMana(requiredMana: Int)
    ...
}

Le principali differenze tra il nuovo meccanismo di errore Swift 2 e 3 e le eccezioni di stile Java / C # / C ++ sono le seguenti:

  • La sintassi è leggermente diversa: do-catch+ try+ deferrispetto alla try-catch-finallysintassi tradizionale .
  • La gestione delle eccezioni di solito comporta tempi di esecuzione molto più elevati nel percorso di eccezione che nel percorso di successo. Questo non è il caso degli errori Swift 2.0, in cui il percorso di successo e il percorso di errore costano all'incirca gli stessi.
  • Tutto il codice di lancio dell'errore deve essere dichiarato, mentre le eccezioni potrebbero essere state lanciate da qualsiasi luogo. Tutti gli errori sono "eccezioni controllate" nella nomenclatura Java. Tuttavia, a differenza di Java, non si specificano errori potenzialmente generati.
  • Le eccezioni rapide non sono compatibili con le eccezioni ObjC. Il tuo do-catchblocco non catturerà alcuna NSException e viceversa, per questo devi usare ObjC.
  • Le eccezioni rapide sono compatibili con le NSErrorconvenzioni del metodo Cocoa di restituzione false(per Boolfunzioni di ritorno) o nil(per AnyObjectfunzioni di ritorno) e passaggio NSErrorPointercon dettagli di errore.

Come ulteriore zucchero sintetico per facilitare la gestione degli errori, ci sono altri due concetti

  • azioni differite (usando la deferparola chiave) che consentono di ottenere lo stesso effetto dei blocchi infine in Java / C # / ecc
  • istruzione guard (usando la guardparola chiave) che ti consente di scrivere un po 'meno codice if / else rispetto al normale codice di controllo / segnalazione degli errori.

Swift 1

Errori di runtime:

Come suggerisce Leandros per la gestione degli errori di runtime (come problemi di connettività di rete, analisi dei dati, apertura del file, ecc.), Dovresti usare NSErrorcome hai fatto in ObjC, perché Foundation, AppKit, UIKit, ecc. Riportano i loro errori in questo modo. Quindi è più una cosa quadro che una cosa linguistica.

Un altro modello frequente che viene utilizzato sono i blocchi di successo / fallimento del separatore come in AFNetworking:

var sessionManager = AFHTTPSessionManager(baseURL: NSURL(string: "yavin4.yavin.planets"))
sessionManager.HEAD("/api/destoryDeathStar", parameters: xwingSquad,
    success: { (NSURLSessionDataTask) -> Void in
        println("Success")
    },
    failure:{ (NSURLSessionDataTask, NSError) -> Void in
        println("Failure")
    })

Tuttavia il blocco di errori ha ricevuto frequentemente l' NSErroristanza, descrivendo l'errore.

Errori del programmatore:

Per errori del programmatore (come accesso fuori limite dell'elemento dell'array, argomenti non validi passati a una chiamata di funzione, ecc.) Hai usato le eccezioni in ObjC. La lingua rapida non sembra avere alcun supporto linguistico per le eccezioni ( parola chiave throw, come catch, ecc.). Tuttavia, poiché la documentazione suggerisce che è in esecuzione sullo stesso runtime di ObjC, e quindi sei ancora in grado di lanciare in NSExceptionsquesto modo:

NSException(name: "SomeName", reason: "SomeReason", userInfo: nil).raise()

Non puoi catturarli in puro Swift, anche se puoi optare per la cattura di eccezioni nel codice ObjC.

La domanda è se dovresti generare eccezioni per errori del programmatore o piuttosto usare affermazioni come Apple suggerisce nella guida linguistica.


20
"problemi di connettività di rete" e "apertura di file" mediante le API Cocoa (NSFileHandle) possono generare eccezioni che devono essere colte. Senza eccezioni in Swift, devi implementare questa parte del tuo programma in Objective-C o eseguire tutto il tuo lavoro utilizzando le API C BSD (che sono entrambi scarse soluzioni). Vedere la documentazione per NSFileHandle.writeData per ulteriori informazioni ... developer.apple.com/library/ios/documentation/Cocoa/Reference/… :
Matt Gallagher,

5
Ancora una volta, nessuna gestione delle eccezioni significa costruzione di oggetti a due fasi con tutti i suoi problemi intrinseci. Vedi stroustrup.com/except.pdf .
Phil,

2
la fatalError(...)è lo stesso pure.
Holex,

8
Per quanto mi piaccia Swift, penso che questa sia una scelta catastrofica, e avendo avuto un assaggio di alcune delle conseguenze, stanno giocando con il fuoco con questa omissione ...
Rob

2
Sì, le eccezioni controllate vengono ora utilizzate con parsimonia, poiché si è scoperto che costringendo il programmatore a catturare le eccezioni hanno poche speranze di recuperare dal codice degli inquinanti in modo da rompere il principio della responsabilità singola. Una classe a livello di dominio non vuole avere a che fare con eccezioni a livello di infrastruttura. Quindi ora le eccezioni non verificate tendono a essere favorite e la parte interessata può prenderle, se del caso. . Controllato = sicuramente recuperabile. Deselezionato = non / potenzialmente recuperabile.
Jasper Blues,

69

Aggiornamento del 9 giugno 2015 - Molto importante

Swift 2.0 viene fornito con try, throwe catchparole chiave e il più emozionante è:

Swift traduce automaticamente i metodi Objective-C che producono errori in metodi che generano un errore in base alla funzionalità di gestione degli errori nativa di Swift.

Nota: i metodi che utilizzano errori, come i metodi delegati o i metodi che accettano un gestore di completamento con un argomento oggetto NSError, non diventano metodi che vengono generati quando importati da Swift.

Estratto da: Apple Inc. "Utilizzo di Swift con Cocoa e Objective-C (Prelavaggio Swift 2)." iBook.

Esempio: (dal libro)

NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *URL = [NSURL fileURLWithPath:@"/path/to/file"];
NSError *error = nil;
BOOL success = [fileManager removeItemAtURL:URL error:&error];
if (!success && error){
    NSLog(@"Error: %@", error.domain);
}

L'equivalente in swift sarà:

let fileManager = NSFileManager.defaultManager()
let URL = NSURL.fileURLWithPath("path/to/file")
do {
    try fileManager.removeItemAtURL(URL)
} catch let error as NSError {
    print ("Error: \(error.domain)")
}

Lancio di un errore:

*errorPtr = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCannotOpenFile userInfo: nil]

Verrà automaticamente propagato al chiamante:

throw NSError(domain: NSURLErrorDomain, code: NSURLErrorCannotOpenFile, userInfo: nil)

Dai libri di Apple, The Swift Programming Language sembra che gli errori debbano essere gestiti usando enum.

Ecco un esempio dal libro.

enum ServerResponse {
    case Result(String, String)
    case Error(String)
}

let success = ServerResponse.Result("6:00 am", "8:09 pm")
let failure = ServerResponse.Error("Out of cheese.")

switch success {
case let .Result(sunrise, sunset):
    let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)."
case let .Error(error):
    let serverResponse = "Failure...  \(error)"
}

Da: Apple Inc. "Il linguaggio di programmazione Swift". iBook. https://itun.es/br/jEUH0.l

Aggiornare

Dai libri di Apple, "Utilizzo di Swift con Cocoa e Objective-C". Le eccezioni di runtime non si verificano utilizzando linguaggi rapidi, quindi è per questo che non hai try-catch. Invece si utilizza il concatenamento opzionale .

Ecco un tratto dal libro:

Ad esempio, nel seguente elenco di codici, la prima e la seconda riga non vengono eseguite perché la proprietà length e il metodo characterAtIndex: non esistono su un oggetto NSDate. La costante myLength è inferita come Int opzionale ed è impostata su zero. È inoltre possibile utilizzare un'istruzione if-let per scartare in modo condizionale il risultato di un metodo a cui l'oggetto potrebbe non rispondere, come mostrato nella riga tre

let myLength = myObject.length?
let myChar = myObject.characterAtIndex?(5)
if let fifthCharacter = myObject.characterAtIndex(5) {
    println("Found \(fifthCharacter) at index 5")
}

Estratto da: Apple Inc. "Utilizzo di Swift con Cocoa e Objective-C". iBook. https://itun.es/br/1u3-0.l


E i libri ti incoraggiano anche a utilizzare il modello di errore del cacao da Objective-C (NSError Object)

La segnalazione degli errori in Swift segue lo stesso modello che ha in Objective-C, con l'ulteriore vantaggio di offrire valori di ritorno opzionali. Nel caso più semplice, si restituisce un valore Bool dalla funzione per indicare se è riuscito o meno. Quando è necessario segnalare il motivo dell'errore, è possibile aggiungere alla funzione un parametro di uscita NSError di tipo NSErrorPointer. Questo tipo è approssimativamente equivalente a NSError ** di Objective-C, con ulteriore sicurezza della memoria e digitazione opzionale. È possibile utilizzare il prefisso e l'operatore per passare un riferimento a un tipo NSError opzionale come oggetto NSErrorPointer, come mostrato nell'elenco di codici riportato di seguito.

var writeError : NSError?
let written = myString.writeToFile(path, atomically: false,
    encoding: NSUTF8StringEncoding,
    error: &writeError)
if !written {
    if let error = writeError {
        println("write failure: \(error.localizedDescription)")
    }
}

Estratto da: Apple Inc. "Utilizzo di Swift con Cocoa e Objective-C". iBook. https://itun.es/br/1u3-0.l


Per l'ultima affermazione, dovrebbe essere: do {try myString.writeToFile (path, atomically: true, encoding: NSUTF8StringEncoding)} catch let error as NSError {print (error)}
Jacky

1
@Jacky Sì, questo è vero per Swift 2.0 sebbene questa risposta sia stata scritta prima del rilascio di Swift 2.0, ho aggiornato la risposta per mostrare il nuovo modo di gestire gli errori in Swift 2.0. Stavo pensando di lasciare questo modo di riferimento, ma prenderò in considerazione l'aggiornamento dell'intera risposta per utilizzare solo swift 2.0
Guilherme Torres Castro,

12

Non ci sono eccezioni in Swift, simile all'approccio dell'Obiettivo-C.

In fase di sviluppo, è possibile utilizzare assertper rilevare eventuali errori che potrebbero apparire e che devono essere corretti prima di passare alla produzione.

L' NSErrorapproccio classico non viene modificato, si invia un NSErrorPointer, che viene popolato.

Breve esempio:

var error: NSError?
var contents = NSFileManager.defaultManager().contentsOfDirectoryAtPath("/Users/leandros", error: &error)
if let error = error {
    println("An error occurred \(error)")
} else {
    println("Contents: \(contents)")
}

6
Ciò solleva due domande: cosa succede quando il codice ObjC che chiamiamo da Swift in realtà genera un'eccezione e se NSError è il nostro oggetto di errore universale come in ObjC?
MDJ,

1
È solo un dato di fatto con Swift che gli inizializzatori non falliscono o non possono fallire?
Phil

11
La gestione delle eccezioni sembra piuttosto sporca
Tash Pemhiwa,

27
Sì, chi ha bisogno di eccezioni quando puoi semplicemente andare in crash? O metti un NSError ** come argomento in tutte le funzioni che dichiari? così ogni f();g();diventa f(&err);if(err) return;g(&err);if(err) return;per il primo mese, poi diventaf(nil);g(nil);hopeToGetHereAlive();
hariseldon78,

2
Questa risposta è sia obsoleta (Swift ora supporta le eccezioni) sia sbagliata (Objective-C supporta le eccezioni.
Rog

11

Il 'Swift Way' raccomandato è:

func write(path: String)(#error: NSErrorPointer) -> Bool { // Useful to curry error parameter for retrying (see below)!
    return "Hello!".writeToFile(path, atomically: false, encoding: NSUTF8StringEncoding, error: error)
}

var writeError: NSError?
let written = write("~/Error1")(error: &writeError)
if !written {
    println("write failure 1: \(writeError!.localizedDescription)")
    // assert(false) // Terminate program
}

Tuttavia preferisco provare / catturare poiché trovo più facile da seguire perché sposta la gestione degli errori in un blocco separato alla fine, questa disposizione viene talvolta chiamata "Percorso d'oro". Fortunatamente puoi farlo con le chiusure:

TryBool {
    write("~/Error2")(error: $0) // The code to try
}.catch {
    println("write failure 2: \($0!.localizedDescription)") // Report failure
    // assert(false) // Terminate program
}

Inoltre è facile aggiungere una funzione di nuovo tentativo:

TryBool {
    write("~/Error3")(error: $0) // The code to try
}.retry {
    println("write failure 3 on try \($1 + 1): \($0!.localizedDescription)")
    return write("~/Error3r")  // The code to retry
}.catch {
    println("write failure 3 catch: \($0!.localizedDescription)") // Report failure
    // assert(false) // Terminate program
}

L'elenco per TryBool è:

class TryBool {
    typealias Tryee = NSErrorPointer -> Bool
    typealias Catchee = NSError? -> ()
    typealias Retryee = (NSError?, UInt) -> Tryee

    private var tryee: Tryee
    private var retries: UInt = 0
    private var retryee: Retryee?

    init(tryee: Tryee) {
        self.tryee = tryee
    }

    func retry(retries: UInt, retryee: Retryee) -> Self {
        self.retries = retries
        self.retryee = retryee
        return self
    }
    func retry(retryee: Retryee) -> Self {
        return self.retry(1, retryee)
    }
    func retry(retries: UInt) -> Self {
        // For some reason you can't write the body as "return retry(1, nil)", the compiler doesn't like the nil
        self.retries = retries
        retryee = nil
        return self
    }
    func retry() -> Self {
        return retry(1)
    }

    func catch(catchee: Catchee) {
        var error: NSError?
        for numRetries in 0...retries { // First try is retry 0
            error = nil
            let result = tryee(&error)
            if result {
                return
            } else if numRetries != retries {
                if let r = retryee {
                    tryee = r(error, numRetries)
                }
            }
        }
        catchee(error)
    }
}

È possibile scrivere una classe simile per testare un valore restituito facoltativo invece del valore Bool:

class TryOptional<T> {
    typealias Tryee = NSErrorPointer -> T?
    typealias Catchee = NSError? -> T
    typealias Retryee = (NSError?, UInt) -> Tryee

    private var tryee: Tryee
    private var retries: UInt = 0
    private var retryee: Retryee?

    init(tryee: Tryee) {
        self.tryee = tryee
    }

    func retry(retries: UInt, retryee: Retryee) -> Self {
        self.retries = retries
        self.retryee = retryee
        return self
    }
    func retry(retryee: Retryee) -> Self {
        return retry(1, retryee)
    }
    func retry(retries: UInt) -> Self {
        // For some reason you can't write the body as "return retry(1, nil)", the compiler doesn't like the nil
        self.retries = retries
        retryee = nil
        return self
    }
    func retry() -> Self {
        return retry(1)
    }

    func catch(catchee: Catchee) -> T {
        var error: NSError?
        for numRetries in 0...retries {
            error = nil
            let result = tryee(&error)
            if let r = result {
                return r
            } else if numRetries != retries {
                if let r = retryee {
                    tryee = r(error, numRetries)
                }
            }
        }
        return catchee(error)
    }
}

La versione TryOptional applica un tipo di ritorno non opzionale che semplifica la successiva programmazione, ad esempio 'Swift Way:

struct FailableInitializer {
    init?(_ id: Int, error: NSErrorPointer) {
        // Always fails in example
        if error != nil {
            error.memory = NSError(domain: "", code: id, userInfo: [:])
        }
        return nil
    }
    private init() {
        // Empty in example
    }
    static let fallback = FailableInitializer()
}

func failableInitializer(id: Int)(#error: NSErrorPointer) -> FailableInitializer? { // Curry for retry
    return FailableInitializer(id, error: error)
}

var failError: NSError?
var failure1Temp = failableInitializer(1)(error: &failError)
if failure1Temp == nil {
    println("failableInitializer failure code: \(failError!.code)")
    failure1Temp = FailableInitializer.fallback
}
let failure1 = failure1Temp! // Unwrap

Utilizzando TryOptional:

let failure2 = TryOptional {
    failableInitializer(2)(error: $0)
}.catch {
    println("failableInitializer failure code: \($0!.code)")
    return FailableInitializer.fallback
}

let failure3 = TryOptional {
    failableInitializer(3)(error: $0)
}.retry {
    println("failableInitializer failure, on try \($1 + 1), code: \($0!.code)")
    return failableInitializer(31)
}.catch {
    println("failableInitializer failure code: \($0!.code)")
    return FailableInitializer.fallback
}

Nota disimballaggio automatico.


7

Modifica: sebbene questa risposta funzioni, è poco più di Objective-C traslitterata in Swift. È stato reso obsoleto dalle modifiche in Swift 2.0. La risposta di Guilherme Torres Castro sopra è un'ottima introduzione al modo preferito di gestire gli errori in Swift. VOS

Ci è voluto un po 'per capirlo, ma penso di averlo aiutato. Sembra brutto però. Nient'altro che una skin sottile rispetto alla versione Objective-C.

Chiamata di una funzione con un parametro NSError ...

var fooError : NSError ? = nil

let someObject = foo(aParam, error:&fooError)

// Check something was returned and look for an error if it wasn't.
if !someObject {
   if let error = fooError {
      // Handle error
      NSLog("This happened: \(error.localizedDescription)")
   }
} else {
   // Handle success
}`

Scrittura della funzione che accetta un parametro di errore ...

func foo(param:ParamObject, error: NSErrorPointer) -> SomeObject {

   // Do stuff...

   if somethingBadHasHappened {
      if error {
         error.memory = NSError(domain: domain, code: code, userInfo: [:])
      }
      return nil
   }

   // Do more stuff...
}


5

Involucro di base attorno all'obiettivo C che ti offre la funzione di prova di cattura. https://github.com/williamFalcon/SwiftTryCatch

Usa come:

SwiftTryCatch.try({ () -> Void in
        //try something
     }, catch: { (error) -> Void in
        //handle error
     }, finally: { () -> Void in
        //close resources
})

Buona idea. Ma chi decide di utilizzarlo deve tenere presente che gli oggetti allocati nel blocco try non vengono deallocati quando viene generata un'eccezione. Ciò può causare problemi agli oggetti zombi e ogni uso di RAII è compromesso (sblocco automatico, commit automatico-sql, rollback automatico-sql ...). Forse c ++ potrebbe aiutarci con una qualche forma di "runAtExit"?
Hariseldon78,

Aggiornamento: ho appena scoperto che c'è un flag in clang per abilitare il rilascio di oggetti al lancio di eccezioni: -fobjc-arc-exceptions. Devo provare se funziona ancora con la versione spostata (penso che dovrebbe)
hariseldon78

Se si utilizza questa opzione, tenere presente che la dimensione del codice aumenta poiché il compilatore deve generare un codice semi-sicuro. Inoltre: fare affidamento su tale funzionalità del compilatore potrebbe non essere la migliore idea. Le eccezioni sono solo per gli errori del programmatore, quindi non vale la pena usare quell'opzione del compilatore solo per risparmiare un po 'di memoria durante lo sviluppo. Se hai delle eccezioni nel tuo codice di produzione, dovresti occuparti della cosa che causa tali eccezioni in primo luogo.
Christian Kienle,

1
Potrebbero esserci situazioni fuori dal tuo controllo. Ad esempio, analizzando json nel formato sbagliato.
William Falcon,

3

Questa è una risposta di aggiornamento per swift 2.0. Non vedo l'ora che funzioni ricco di modelli di gestione degli errori come in Java. Alla fine hanno annunciato la buona notizia. Qui

Modello di gestione degli errori: il nuovo modello di gestione degli errori in Swift 2.0 sembrerà immediatamente naturale, con parole chiave di prova, lancio e acquisizione familiari . Soprattutto, è stato progettato per funzionare perfettamente con gli SDK di Apple e NSError. In effetti, NSError è conforme a ErrorType di Swift. Avrai sicuramente voglia di guardare la sessione del WWDC su Novità di Swift per saperne di più.

per esempio :

func loadData() throws { }
func test() {
do {
    try loadData()
} catch {
    print(error)
}}

3

Come ha detto Guilherme Torres Castro, a Swift 2.0, try, catch, dopossono essere utilizzati nella programmazione.

Ad esempio, in CoreData recuperare il metodo di dati, invece di mettere &errorcome parametro in managedContext.executeFetchRequest(fetchRequest, error: &error), ora abbiamo solo bisogno di utilizzare l'uso managedContext.executeFetchRequest(fetchRequest)e poi gestire l'errore con try, catch( mela Document Link )

do {
   let fetchedResults = try managedContext.executeFetchRequest(fetchRequest) as? [NSManagedObject]
   if let results = fetchedResults{
      people = results
   }
} catch {
   print("Could not fetch")
}

Se hai già scaricato xcode7 Beta. Prova a cercare errori di lancio in Documentazione e Riferimento API e scegli il primo risultato che mostra, ti dà un'idea di base su cosa si può fare per questa nuova sintassi. Tuttavia, la documentazione completa non è ancora disponibile per molte API.

Altre tecniche di gestione degli errori più elaborate sono disponibili in

Novità di Swift (Sessione 2015 106 28m30s)



1

Lib piacevole e semplice da gestire eccezione: TryCatchFinally-Swift

Come pochi altri si avvolge attorno alle caratteristiche dell'eccezione C dell'obiettivo.

Usalo in questo modo:

try {
    println("  try")
}.catch { e in
    println("  catch")
}.finally {
    println("  finally")
}

Ho aggiunto un campione :)
Morten Holmgaard il

Vale probabilmente la pena menzionare l'opinione degli autori: "Attenzione: questo è un trucco per il divertimento e il male. Resistere alla tentazione di usarlo."
jbat100,

1

A partire da Swift 2, come altri hanno già accennato, la gestione degli errori si ottiene meglio attraverso l'uso delle enumerazioni do / try / catch e ErrorType. Funziona abbastanza bene per i metodi sincroni, ma è necessaria un po 'di intelligenza per la gestione asincrona degli errori.

Questo articolo ha un ottimo approccio a questo problema:

https://jeremywsherman.com/blog/2015/06/17/using-swift-throws-with-completion-callbacks/

Riassumere:

// create a typealias used in completion blocks, for cleaner code
typealias LoadDataResult = () throws -> NSData

// notice the reference to the typealias in the completionHandler
func loadData(someID: String, completionHandler: LoadDataResult -> Void)
    {
    completionHandler()
    }

quindi, la chiamata al metodo sopra sarebbe la seguente:

self.loadData("someString",
    completionHandler:     
        { result: LoadDataResult in
        do
            {
            let data = try result()
            // success - go ahead and work with the data
            }
        catch
            {
            // failure - look at the error code and handle accordingly
            }
        })

Sembra un po 'più pulito che avere un callback di ErrorHandler separato passato alla funzione asincrona, che era come sarebbe stato gestito prima di Swift 2.


0

Quello che ho visto è che a causa della natura del dispositivo non vuoi lanciare un sacco di errori criptici nella gestione dei messaggi all'utente. Questo è il motivo per cui la maggior parte delle funzioni restituisce valori opzionali, quindi basta codificare per ignorare il facoltativo. Se una funzione ritorna nulla, il che significa che ha fallito, puoi far apparire un messaggio o altro.


1
La restituzione di uno zero non restituisce informazioni sulla natura dell'errore. Se viene restituito un oggetto errore quando si verifica un errore, a seconda dell'errore, il programmatore può scegliere di ignorarlo, gestirlo, lasciarlo bolle o "pop un messaggio o altro". Sapere è potere.
Vince O'Sullivan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.