La sortie de Swift 2.0 a introduit d’important concept au langage dont celui de la gestion des erreurs. En effet, dans un soucis de rendre le langage plus sûr il lui fallait pouvoir gérer les erreurs d’une manière simple, cohérente et facile d’utilisation. Dans ce petit cours nous allons donc traiter de ce sujet en introduisant les nouvelles structures de contrôle do-try-catch
et de la manière dont les NSError
et autres Error
sont gérer.
Représenter et lever des erreurs
En Swift 2.0, toutes les erreurs doivent être conforme au protocole ErrorType
. Même NSError
qui est un vestige du framework Cocoa
se conforme bien évidement à ce protocole. Il est d’usage d’utiliser des énumérations afin de distinguer les différents type d’erreur qui pourrait survenir. Prenons par example le cas d’une gestion de compte bancaire qui peut soulever plusieurs erreurs quand on essaye de faire passer une transaction. Voici ce que l’on pourrait écrire :
enum AccountError: ErrorType {
case TransactionExceedsFunds
case NonPositiveTransactionNotAllowed(amount: Int)
}
Ici on définit un type AccountError
qui hérite de ErrorType
(qui sera donc considérer comme un objet Erreur par le runtime) qui définit 2 cas d’erreur :
TransactionExceedsFunds
: le montant de la transaction est supérieur au solde du compte.NonPositiveTransactionNotAllowed
: le montant de la transaction doit être positif (il contient par la même occasion le montant de la transaction).
Lever une erreur (car on utilise pas le terme exception en Swift) vous permet d’indiquer que quelque chose d’inattendu c’est produit lors de l’exécution du code et qu’il ne peut pas continuer si l’on ne traire pas ce problème. Pour lever une erreur il faut utilise le mot clé throw
suivi de l’erreur. Par example, le code suivant renvoie une erreur pour indiquer que les fonds sur le compte sont insuffisant :
throw AccountError.TransactionExceedsFunds
Nous allons maintenant voir comment on gère ces erreurs.
Gérer les erreurs
Quand une erreur est envoyée il faut être capable de la gérer. Pour cela il a 4 façons de faire en Swift :
- Laisser se propager l’erreur en dehors de la fonction utilisant le mot clé
throws
pour que l’appelant la gère lui même. - Attraper l’erreur nous même en utilisant une instruction
do-catch
. - Gérer l’erreur comme une optionnelle avec le mot clé
try?
. - Affirmer que l’erreur ne se produira jamais (à nos risques et périls) en utilisant le mot clé
try!
.
Reprenons l’example de notre compte en banque :
struct BankAccount {
var fund: Int
mutating func withdraw(amount: Int) throws {
guard amount < fund else {
throw AccountError.TransactionExceedsFunds
}
guard amount > 0 else {
throw AccountError.NonPositiveTransactionNotAllowed(amount: amount)
}
fund -= amount
}
}
Cette fonction est marqué avec le mot clé throws
, ce qui permet de déléguer la gestion des erreur à la méthode appelante. Pour cela il faut utiliser les instructions do-try-catch
:
var bankAccount = BankAccount(fund: 500)
do {
try bankAccount.withdraw(400)
// ...
}
catch AccountError.TransactionExceedsFunds {
print("Plus de fond")
}
catch AccountError.NonPositiveTransactionNotAllowed(let amount) {
print("Transaction invalide : \(amount)")
}
Alors ici nous faisons appel à la fonction withdraw
. Seulement cette fonction peut renvoyer des erreurs, donc pour l’appeler nous utilisons le mot clé try
. Cela veut dire que nous allons essayer d’exécuter cette méthode et que si la moindre erreur survient l’exécution du block s’arrête là et la structure do-catch
prend le relai. Si aucune erreur n’est levé l’exécution du bloc continu normalement. Les catch
sont appelés uniquement si une erreur survient et le uniquement catch
correspondant au type de l’erreur donné est exécuté.
Le mot clé try
nous permet de savoir directement que l’exécution de cette méthode est potentiellement dangereuse et qu’il faut y porter un intérêt tout particulier.
Nous aurions aussi pû utiliser le mot clé try?
ou try!
et vous passer du do-catch
:
var bankAccount = BankAccount(fund: 500)
try? bankAccount.withdraw(400)
// ou
try! try bankAccount.withdraw(400)
Avec le try?
on décide juste de ne rien faire si une erreur survient alors qu’avec le try!
si une erreur survient le programme va être stopper. Donc il faut faire très attention quant à son utilisation.
Et finalement ?
En Swift 2.0 il n’existe pas de finally
comme dans d’autres langages. A la place nous avons une instruction appelé defer
qui peut être utiliser en toute circonstance et qui est exécuter à la fin d’un bloc de code quoi qu’il arrive.
Nous en avons déjà parlé dans un précédent article, donc n’hésitez pas à aller y faire un tour pour en savoir un peu plus.
Conclusion
Swift 2.0 introduit de nouvelle manière de gérer les erreurs qui permettent un réel compromit entre qualité du code, lisibilité et simplicité. Au travers de cette gestion Swift 2.0 se tourne résolument du coté des langages modernes en apportant de nouveaux cadres qui évoluerons certainement avec Swift 3.0.
Bonne lecture.
Félicitations pour vos articles qui défrichent ce nouveau langage qu’est swift et contribuent à le rendre plus limpide.