Ao chamar uma função declarada com throws
no Swift, você deve anotar o site de chamada da função com try
ou try!
. Por exemplo, dada uma função de arremesso:
func willOnlyThrowIfTrue(value: Bool) throws {
if value { throw someError }
}
Essa função pode ser chamada como:
func foo(value: Bool) throws {
try willOnlyThrowIfTrue(value)
}
Aqui, anotamos a chamada com try
, que chama ao leitor que esta função pode gerar uma exceção, e as seguintes linhas de código podem não ser executadas. Também temos que anotar esta função com throws
, porque essa função pode lançar uma exceção (ou seja, quando willOnlyThrowIfTrue()
lança, então foo
, automaticamente, a exceção será repetida para cima.
Se você deseja chamar uma função que é declarada como possivelmente lançada, mas que você sabe que não será lançada no seu caso porque está fornecendo a entrada correta, você pode usar try!
.
func bar() {
try! willOnlyThrowIfTrue(false)
}
Dessa forma, quando você garante que o código não será lançado, não precisará inserir um código adicional para desabilitar a propagação de exceção.
try!
é imposta no tempo de execução: se você usar try!
e a função acabar sendo lançada, a execução do seu programa será encerrada com um erro de tempo de execução.
A maioria dos códigos de manipulação de exceções deve se parecer com o acima: ou você simplesmente propaga as exceções para cima quando elas ocorrem, ou configura condições para que as exceções possíveis sejam descartadas. Qualquer limpeza de outros recursos no seu código deve ocorrer por destruição de objeto (ou seja deinit()
) ou, às vezes, por defer
código ed.
func baz(value: Bool) throws {
var filePath = NSBundle.mainBundle().pathForResource("theFile", ofType:"txt")
var data = NSData(contentsOfFile:filePath)
try willOnlyThrowIfTrue(value)
// data and filePath automatically cleaned up, even when an exception occurs.
}
Se, por qualquer motivo, você tiver um código de limpeza que precisa ser executado, mas não está em uma deinit()
função, você pode usá-lo defer
.
func qux(value: Bool) throws {
defer {
print("this code runs when the function exits, even when it exits by an exception")
}
try willOnlyThrowIfTrue(value)
}
A maioria dos códigos que lida com exceções simplesmente os propaga para os chamadores, fazendo a limpeza no caminho via deinit()
ou defer
. Isso ocorre porque a maioria dos códigos não sabe o que fazer com erros; ele sabe o que deu errado, mas não possui informações suficientes sobre o que algum código de nível superior está tentando fazer para saber o que fazer com o erro. Ele não sabe se a apresentação de uma caixa de diálogo ao usuário é apropriada, ou se deve tentar novamente, ou se algo mais é apropriado.
Código de nível superior, no entanto, deve saber exatamente o que fazer no caso de qualquer erro. Portanto, as exceções permitem que erros específicos surjam de onde ocorrem inicialmente para onde podem ser manipulados.
O tratamento de exceções é feito por meio de catch
instruções.
func quux(value: Bool) {
do {
try willOnlyThrowIfTrue(value)
} catch {
// handle error
}
}
Você pode ter várias instruções de captura, cada uma capturando um tipo diferente de exceção.
do {
try someFunctionThatThowsDifferentExceptions()
} catch MyErrorType.errorA {
// handle errorA
} catch MyErrorType.errorB {
// handle errorB
} catch {
// handle other errors
}
Para mais detalhes sobre as melhores práticas, com exceções, consulte http://exceptionsafecode.com/ . Ele é voltado especificamente para C ++, mas depois de examinar o modelo de exceção Swift, acredito que o básico também se aplica a Swift.
Para detalhes sobre a sintaxe do Swift e o modelo de tratamento de erros, consulte o livro A linguagem de programação Swift (Swift 2 Pré-lançamento) .