Tratamento de erros em linguagem rápida

190

Eu não li muito sobre o Swift, mas uma coisa que notei é que não há exceções. Então, como eles lidam com erros no Swift? Alguém encontrou algo relacionado ao tratamento de erros?

peko
fonte
1
Encontrei mensagens de erro como no Obj-C: o
Arbitur
13
@Arbitur da boa e velha maneira segfault?
Peko
Criado um NSTimer em Swift e quando eu grafada a função que ele caiu e deu-me um erro dizendo que não poderia encontrar o método :)
Arbitur
3
Você pode adicionar suporte try-catch para Swift, seguindo as instruções deste artigo: medium.com/@_willfalcon/adding-try-catch-to-swift-71ab27bcb5b8
William Falcon
@peko Como você lida com um segfault no Swift? Eu não acho que é possível a partir de agora, o que, infelizmente, faz alguns erros irrecuperáveis
Orlin Georgiev

Respostas:

148

Swift 2 e 3

As coisas mudaram um pouco no Swift 2, pois há um novo mecanismo de tratamento de erros, que é um pouco mais semelhante às exceções, mas diferente em detalhes.

1. Indicando possibilidade de erro

Se a função / método quiser indicar que pode gerar um erro, deve conter uma throwspalavra-chave como esta

func summonDefaultDragon() throws -> Dragon

Nota: não há especificação para o tipo de erro que a função realmente pode gerar. Essa declaração simplesmente declara que a função pode lançar uma instância de qualquer tipo implementando ErrorType ou não está lançando.

2. Chamando a função que pode gerar erros

Para chamar a função, você precisa usar a palavra-chave try, como esta

try summonDefaultDragon()

esta linha normalmente deve estar presente com bloco de captura e captura como este

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: a cláusula catch usa todos os recursos avançados da correspondência de padrões Swift, para que você seja muito flexível aqui.

Você pode propagar o erro, se estiver chamando uma função de lançamento de uma função que é marcada com throws palavra-chave:

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

Como alternativa, você pode chamar a função de arremesso usando try?:

let dragonOrNil = try? summonDefaultDragon()

Dessa forma, você obtém o valor de retorno ou nulo, se ocorrer algum erro. Usando esse caminho, você não obtém o objeto de erro.

O que significa que você também pode combinar try?com declarações úteis como:

if let dragon = try? summonDefaultDragon()

ou

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

Por fim, você pode decidir que sabe que o erro não ocorrerá (por exemplo, porque você já verificou os pré-requisitos) e usar a try!palavra-chave:

let dragon = try! summonDefaultDragon()

Se a função realmente gerar um erro, você receberá um erro de tempo de execução no aplicativo e o aplicativo será encerrado.

3. Lançando um erro

Para gerar um erro, use a palavra-chave throw como esta

throw DragonError.dragonIsMissing

Você pode lançar qualquer coisa que esteja em conformidade com o ErrorTypeprotocolo. Para iniciantes, em NSErrorconformidade com esse protocolo, mas você provavelmente gostaria de usar o enum, ErrorTypeque permite agrupar vários erros relacionados, potencialmente com dados adicionais, como este

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

As principais diferenças entre o novo mecanismo de erro Swift 2 e 3 e as exceções no estilo Java / C # / C ++ são as seguintes:

  • A sintaxe é um pouco diferente: do-catch+ try+ defervs tradicionaltry-catch-finally sintaxe .
  • O tratamento de exceções geralmente gera um tempo de execução muito maior no caminho da exceção do que no caminho do sucesso. Este não é o caso dos erros do Swift 2.0, onde o caminho do sucesso e o caminho do erro custam aproximadamente o mesmo.
  • Todo o código de lançamento de erro deve ser declarado, enquanto as exceções podem ter sido lançadas de qualquer lugar. Todos os erros são "exceções verificadas" na nomenclatura Java. No entanto, ao contrário do Java, você não especifica erros potencialmente gerados.
  • As exceções rápidas não são compatíveis com as exceções de ObjC. Seu do-catchbloco não capturará nenhum NSException e vice-versa, para isso você deve usar o ObjC.
  • As exceções rápidas são compatíveis com as NSErrorconvenções do método Cocoa de retornar false(para Boolretornar funções) ou nil(para AnyObjectretornar funções) e passar NSErrorPointercom detalhes de erro.

Como um açúcar sintático extra para facilitar o tratamento de erros, existem mais dois conceitos

  • ações adiadas (usando defer palavra-chave) que permitem obter o mesmo efeito dos blocos finalmente em Java / C # / etc
  • declaração de guarda (usando a guardpalavra-chave), que permite escrever um código se / else menos que no código normal de verificação / sinalização de erros.

Swift 1

Erros de tempo de execução:

Como Leandros sugere para lidar com erros de tempo de execução (como problemas de conectividade de rede, análise de dados, arquivo de abertura, etc.), você deve usar NSErrorcomo no ObjC, porque o Foundation, AppKit, UIKit, etc. relatam seus erros dessa maneira. Portanto, é mais uma coisa de estrutura do que de linguagem.

Outro padrão frequente que está sendo usado são os blocos de sucesso / falha do separador, como no 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")
    })

Ainda assim, o bloco de falha recebeu a NSErrorinstância frequentemente , descrevendo o erro.

Erros do programador:

Para erros do programador (como acesso fora do limite do elemento da matriz, argumentos inválidos passados ​​para uma chamada de função, etc.), você usou exceções no ObjC. Linguagem Swift não parece ter qualquer suporte ao idioma para exceções (como throw, catch, etc palavra-chave). No entanto, como a documentação sugere, ele está sendo executado no mesmo tempo de execução que o ObjC e, portanto, você ainda pode jogar NSExceptionsassim:

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

Você simplesmente não pode capturá-los no Swift puro, embora possa optar por capturar exceções no código ObjC.

A questão é se você deve lançar exceções para erros de programadores ou usar afirmações, como a Apple sugere no guia de idiomas.

MDJ
fonte
20
"problemas de conectividade de rede" e "abertura de arquivos" usando as APIs do Cocoa (NSFileHandle) podem gerar exceções que precisam ser detectadas. Sem exceções no Swift, você precisa implementar esta parte do seu programa no Objective-C ou executar todo o seu trabalho usando as APIs do BSD C (que são soluções alternativas precárias). Consulte a documentação do NSFileHandle.writeData para obter mais informações: developer.apple.com/library/ios/documentation/Cocoa/Reference/… :
Matt Gallagher
5
Novamente, nenhuma manipulação de exceção significa construção de objetos em dois estágios com todos os seus problemas inerentes. Consulte stroustrup.com/except.pdf .
Phil
2
o fatalError(...)é o mesmo também.
holex
8
Por mais que eu como Swift, penso que esta é uma escolha catastrófica, e ter tido um sabor de algumas das consequências, eles estão brincando com fogo com esta omissão ...
Rob
2
Sim, as exceções verificadas agora são usadas com moderação, porque foi constatado que, ao forçar o programador a capturar exceções, eles têm pouca esperança de se recuperar do código de poluentes de maneira única, quebrando os princípios. Uma classe no nível do domínio não deseja lidar com exceções da camada de infraestrutura. Portanto, agora, as exceções não verificadas tendem a ser favorecidas e a parte interessada pode capturá-las, se apropriado. . Verificado = definitivamente recuperável. Desmarcado = não / potencialmente recuperável.
Jasper azuis
69

Atualização 9 de junho de 2015 - Muito importante

Swift 2.0 vem com try, throwe catchpalavras-chave e o mais interessante é:

O Swift converte automaticamente os métodos Objective-C que produzem erros em métodos que geram um erro de acordo com a funcionalidade nativa de manipulação de erros do Swift.

Nota: Os métodos que consomem erros, como delegar métodos ou métodos que usam um manipulador de conclusão com um argumento de objeto NSError, não se tornam métodos lançados quando importados pelo Swift.

Trecho de: Apple Inc. “Usando o Swift com cacau e o Objective-C (pré-lançamento do Swift 2).” iBooks.

Exemplo: (do livro)

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);
}

O equivalente em swift será:

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)")
}

Lançando um erro:

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

Será propagado automaticamente para o chamador:

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

Nos livros da Apple, parece que a linguagem de programação Swift parece que os erros devem ser tratados usando enum.

Aqui está um exemplo do livro.

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)"
}

De: Apple Inc. “A linguagem de programação Swift”. iBooks. https://itun.es/br/jEUH0.l

Atualizar

Dos jornais da Apple, "Usando Swift com cacau e Objective-C". As exceções de tempo de execução não ocorrem usando idiomas rápidos, é por isso que você não tem o try-catch. Em vez disso, você usa o encadeamento opcional .

Aqui está um trecho do livro:

Por exemplo, na lista de códigos abaixo, a primeira e a segunda linhas não são executadas porque a propriedade length e o characterAtIndex: method não existem em um objeto NSDate. A constante myLength é inferida como um Int opcional e é definida como nil. Você também pode usar uma instrução if-let para desembrulhar condicionalmente o resultado de um método ao qual o objeto pode não responder, conforme mostrado na linha três

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

Trecho de: Apple Inc. "Usando Swift com cacau e Objective-C". iBooks. https://itun.es/br/1u3-0.l


E os livros também incentivam você a usar o padrão de erro de cacau do Objective-C (NSError Object)

O relatório de erros no Swift segue o mesmo padrão do Objective-C, com o benefício adicional de oferecer valores de retorno opcionais. No caso mais simples, você retorna um valor Bool da função para indicar se ele foi ou não bem-sucedido. Quando você precisar relatar o motivo do erro, poderá adicionar à função um parâmetro de saída NSError do tipo NSErrorPointer. Esse tipo é aproximadamente equivalente ao NSError do Objective-C **, com segurança adicional na memória e digitação opcional. Você pode usar o prefixo & operator para passar uma referência a um tipo NSError opcional como um objeto NSErrorPointer, conforme mostrado na lista de códigos abaixo.

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)")
    }
}

Trecho de: Apple Inc. "Usando Swift com cacau e Objective-C". iBooks. https://itun.es/br/1u3-0.l

Guilherme Torres Castro
fonte
Para a última declaração, que deve ser: não {try myString.writeToFile (caminho, atomicamente: true, codificando: NSUTF8StringEncoding)} erro captura let como NSError {print (erro)}
Jacky
1
@ Jacky Sim, isso é verdade para o swift 2.0, embora essa resposta tenha sido escrita antes do lançamento do swift 2.0, atualizei a resposta para mostrar a nova maneira de lidar com os erros no swift 2.0. Eu estava pensando em deixar esse caminho para referência, mas considerarei atualizar toda a resposta para usar apenas o swift 2.0 #
Guilherme Torres Castro
12

Não há exceções no Swift, semelhante à abordagem do Objective-C.

No desenvolvimento, você pode usar assertpara capturar os erros que possam aparecer e precisam ser corrigidos antes de ir para a produção.

A NSErrorabordagem clássica não é alterada, você envia um NSErrorPointer, que é preenchido.

Breve exemplo:

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)")
}
Leandros
fonte
6
Isso levanta duas questões: o que acontece quando o código ObjC que chamamos de Swift realmente lança uma exceção, e se NSError é nosso objeto de erro universal como no ObjC?
MDJ
1
É apenas um fato da vida da Swift que os inicializadores não falham ou não podem falhar?
Phil
11
O tratamento de exceção parece bastante sujo
Tash Pemhiwa
27
Sim, quem precisa de exceções quando você pode simplesmente travar? Ou coloque um NSError ** como argumento em todas as funções que você declara? de modo que cada f();g();torna-se f(&err);if(err) return;g(&err);if(err) return;para o primeiro mês, então ele acaba de se tornarf(nil);g(nil);hopeToGetHereAlive();
hariseldon78
2
Esta resposta é ultrapassada (Swift agora suporta exceções) e erradas (Objective-C faz exceções de apoio.
Rog
11

O 'Swift Way' recomendado é:

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
}

No entanto, prefiro try / catch, pois acho mais fácil seguir porque move o tratamento de erros para um bloco separado no final, esse arranjo às vezes é chamado de "Caminho Dourado". Sorte que você pode fazer isso com fechamentos:

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

Também é fácil adicionar um recurso de nova tentativa:

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
}

A lista para o 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)
    }
}

Você pode escrever uma classe semelhante para testar um valor retornado opcional em vez de valor 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)
    }
}

A versão TryOptional aplica um tipo de retorno não opcional que facilita a programação subseqüente, por exemplo, '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

Usando o 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
}

Observe o desempacotamento automático.

Howard Lovatt
fonte
7

Editar: Embora esta resposta funcione, é pouco mais que o Objective-C transliterado para o Swift. Foi tornado obsoleto pelas alterações no Swift 2.0. A resposta de Guilherme Torres Castro acima é uma introdução muito boa à maneira preferida de lidar com erros no Swift. VOS

Demorou um pouco para descobrir isso, mas acho que já o sussurrei. Parece feio embora. Nada além de uma capa fina sobre a versão Objective-C.

Chamando uma função com um parâmetro 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
}`

Escrevendo a função que recebe um parâmetro de erro ...

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...
}
Vince O'Sullivan
fonte
5

Wrapper básico em torno do objetivo C que fornece o recurso try catch. https://github.com/williamFalcon/SwiftTryCatch

Use como:

SwiftTryCatch.try({ () -> Void in
        //try something
     }, catch: { (error) -> Void in
        //handle error
     }, finally: { () -> Void in
        //close resources
})
William Falcon
fonte
Boa ideia. Mas quem decide usar isso deve ter em mente que os objetos alocados no bloco try não são desalocados quando uma exceção é lançada. Isso pode causar problemas em objetos zumbis e todo uso do RAII é comprometido (desbloqueio automático, auto-sql-commit, auto-sql-rollback ...). Talvez o c ++ possa nos ajudar com alguma forma de "runAtExit"?
hariseldon78
Atualização: Acabei de descobrir que existe um sinalizador no clang para permitir o lançamento de objetos na exceção, lançando: -fobjc-arc-exceptions. I deve tentar se ele ainda funciona com a versão enrolado (eu acho que deveria)
hariseldon78
Se você usar esta opção, lembre-se de que o tamanho do código aumenta, pois o compilador precisa gerar código seguro para sem exceção. Além disso: contar com esse recurso de compilador pode não ser a melhor ideia. As exceções são apenas para erros do programador, portanto, não é necessário procurar nessa opção do compilador apenas para economizar um pouco de memória durante o desenvolvimento. Se houver exceções no código de produção, você deve lidar com a coisa que está causando essas exceções em primeiro lugar.
Christian Kienle
1
Pode haver situações fora de seu controle. Por exemplo, analisando json no formato errado.
William Falcon
3

Esta é uma resposta de atualização para o Swift 2.0. Estou ansioso por um modelo de manipulação de erros rico em recursos, como em java. Finalmente, eles anunciaram as boas novas. aqui

Modelo de tratamento de erros: o novo modelo de tratamento de erros no Swift 2.0 parecerá instantaneamente natural, com palavras-chave familiares de tentativa, lançamento e captura . O melhor de tudo foi que ele foi projetado para funcionar perfeitamente com os SDKs da Apple e o NSError. De fato, o NSError está em conformidade com o ErrorType de um Swift. Você definitivamente vai querer assistir à sessão da WWDC no What's New in Swift para ouvir mais sobre isso.

por exemplo :

func loadData() throws { }
func test() {
do {
    try loadData()
} catch {
    print(error)
}}
Paraneetharan Saravanaperumal
fonte
3

Como Guilherme Torres Castro disse, em Swift 2,0, try, catch,do pode ser utilizado na programação.

Por exemplo, em CoreData buscar método de dados, em vez de colocar &errorcomo um parâmetro para o managedContext.executeFetchRequest(fetchRequest, error: &error), agora só precisa usar uso managedContext.executeFetchRequest(fetchRequest)e, em seguida, manipular o erro com try, catch( a Apple Document Link )

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

Se você já baixou o xcode7 Beta. Tente pesquisar lançando erros em Documentations and API Reference e escolha o primeiro resultado exibido, pois fornece uma idéia básica do que pode ser feito para essa nova sintaxe. No entanto, a documentação completa ainda não está publicada para muitas APIs.

Técnicas mais sofisticadas de tratamento de erros podem ser encontradas em

O que há de novo no Swift (2015 Sessão 106 28m30s)

Zingoer
fonte
1

Lib agradável e simples para lidar com a exceção: TryCatchFinally-Swift

Como alguns outros, ele envolve os recursos de exceção do objetivo C.

Use-o assim:

try {
    println("  try")
}.catch { e in
    println("  catch")
}.finally {
    println("  finally")
}
Morten Holmgaard
fonte
Eu adicionei uma amostra :)
Morten Holmgaard
Provavelmente vale a pena mencionar a opinião dos autores: "Aviso: este é um truque para diversão e maldade. Resista à tentação de usá-lo".
precisa saber é
1

Começando com o Swift 2, como outros já mencionaram, a manipulação de erros é melhor realizada através do uso de enums do / try / catch e ErrorType. Isso funciona muito bem para métodos síncronos, mas é necessária um pouco de inteligência para o tratamento de erros assíncronos.

Este artigo possui uma ótima abordagem para esse problema:

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

Para resumir:

// 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()
    }

então, a chamada para o método acima seria a seguinte:

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
            }
        })

Isso parece um pouco mais limpo do que ter um retorno de chamada errorHandler separado passado para a função assíncrona, que era como isso seria tratado antes do Swift 2.

Gene Loparco
fonte
0

O que eu vi é que, devido à natureza do dispositivo, você não deseja lançar um monte de mensagens enigmáticas de manipulação de erros para o usuário. É por isso que a maioria das funções retorna valores opcionais, então você apenas codifica para ignorar o opcional. Se uma função retornar nula, significando que falhou, você poderá exibir uma mensagem ou o que for.

cheborneck
fonte
1
Retornar nulo não retorna nenhuma informação sobre a natureza do erro. Se um objeto de erro for retornado quando ocorrer um erro, dependendo do erro, o programador poderá optar por ignorá-lo, manipulá-lo, deixá-lo borbulhar ou "exibir uma mensagem ou o que for". Conhecimento é poder.
Vince O'Sullivan