Gestion des erreurs en Swift 2.0

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 :

  1. 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.
  2. Attraper l’erreur nous même en utilisant une instruction do-catch.
  3. Gérer l’erreur comme une optionnelle avec le mot clé try?.
  4. 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.

1 Etoile2 Etoiles3 Etoiles4 Etoiles5 Etoiles (2 votes, average: 5,00 out of 5)
Loading...

Aucun commentaire

Annuler

Time limit is exhausted. Please reload CAPTCHA.

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

  1. Lebreton · 9 février 2016

    Félicitations pour vos articles qui défrichent ce nouveau langage qu’est swift et contribuent à le rendre plus limpide.