Lorsque vous appelez une fonction déclarée avec throws
dans Swift, vous devez annoter le site d'appel de fonction avec try
ou try!
. Par exemple, étant donné une fonction de lancement:
func willOnlyThrowIfTrue(value: Bool) throws {
if value { throw someError }
}
cette fonction peut être appelée comme:
func foo(value: Bool) throws {
try willOnlyThrowIfTrue(value)
}
Ici, nous annotons l'appel avec try
, qui appelle le lecteur que cette fonction peut lever une exception et que les lignes de code suivantes peuvent ne pas être exécutées. Nous avons aussi annoter cette fonction avec throws
, parce que cette fonction pourrait lancer une exception (quand willOnlyThrowIfTrue()
lancers francs, puis foo
sera automatiquement réémettre l'exception vers le haut.
Si vous voulez appeler une fonction qui est déclarée comme pouvant être lancée, mais dont vous savez qu'elle ne la lancera pas dans votre cas parce que vous lui donnez une entrée correcte, vous pouvez utiliser try!
.
func bar() {
try! willOnlyThrowIfTrue(false)
}
De cette façon, lorsque vous garantissez que le code ne sera pas lancé, vous n'avez pas à insérer de code standard supplémentaire pour désactiver la propagation des exceptions.
try!
est appliqué à l'exécution: si vous utilisez try!
et que la fonction finit par lancer, l'exécution de votre programme se terminera par une erreur d'exécution.
La plupart des codes de gestion d'exceptions devraient ressembler à ce qui précède: soit vous propagez simplement les exceptions vers le haut lorsqu'elles se produisent, soit vous définissez des conditions telles que les exceptions éventuelles sont exclues. Tout nettoyage des autres ressources de votre code doit se faire via la destruction d'objets (ie deinit()
), ou parfois via le defer
code 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.
}
Si, pour une raison quelconque, vous avez du code de nettoyage qui doit s'exécuter mais qui n'est pas deinit()
fonction, vous pouvez utiliser 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)
}
La plupart du code qui traite les exceptions les fait simplement se propager vers le haut aux appelants, effectuant le nettoyage en cours de route via deinit()
ou defer
. C'est parce que la plupart du code ne sait pas quoi faire avec les erreurs; il sait ce qui s'est mal passé, mais il n'a pas suffisamment d'informations sur ce qu'un code de niveau supérieur essaie de faire pour savoir quoi faire à propos de l'erreur. Il ne sait pas si la présentation d'une boîte de dialogue à l'utilisateur est appropriée, ou s'il doit réessayer, ou si quelque chose d'autre est approprié.
Cependant, le code de niveau supérieur doit savoir exactement quoi faire en cas d'erreur. Ainsi, les exceptions permettent à des erreurs spécifiques de remonter de l'endroit où elles se produisent initialement à l'endroit où elles peuvent être traitées.
La gestion des exceptions se fait via catch
instructions.
func quux(value: Bool) {
do {
try willOnlyThrowIfTrue(value)
} catch {
// handle error
}
}
Vous pouvez avoir plusieurs instructions catch, chacune interceptant un type d'exception différent.
do {
try someFunctionThatThowsDifferentExceptions()
} catch MyErrorType.errorA {
// handle errorA
} catch MyErrorType.errorB {
// handle errorB
} catch {
// handle other errors
}
Pour plus d'informations sur les bonnes pratiques avec exceptions, consultez http://exceptionsafecode.com/ . Il est spécifiquement destiné au C ++, mais après avoir examiné le modèle d'exception Swift, je pense que les bases s'appliquent également à Swift.
Pour plus de détails sur la syntaxe Swift et le modèle de gestion des erreurs, consultez le livre The Swift Programming Language (Swift 2 Prerelease) .