Gestion des erreurs en Swift : try/catch et bien plus — guide complet
La gestion des erreurs est l'un des sujets clés du développement iOS et macOS. Le langage Swift implémente un système de gestion des défaillances puissant et élégant qui va bien au-delà du simple try/catch. Comprendre ces mécanismes permet d'écrire un code fiable, prévisible et sécurisé. Dans cet article, nous aborderons tous les aspects : de la déclaration de base des erreurs aux techniques avancées avec les valeurs optionnelles et les déinitialisateurs.
Les bases : le protocole Error et le mot-clé throws
En Swift, toute erreur doit être conforme au protocole Error. On utilise généralement des énumérations (enum) pour cela. Prenons un exemple simple — la validation d'un mot de passe :
enum PasswordError: Error { case tooShort case missingDigit case missingUppercase}
func validatePassword(_ password: String) throws { guard password.count >= 8 else { throw PasswordError.tooShort } guard password.rangeOfCharacter(from: .decimalDigits) != nil else { throw PasswordError.missingDigit } guard password.rangeOfCharacter(from: .uppercaseLetters) != nil else { throw PasswordError.missingUppercase } print("Mot de passe valide")}Le mot-clé throws dans la déclaration de la fonction indique au compilateur que l'exécution peut être interrompue par une erreur. L'appel d'une telle fonction nécessite une syntaxe spéciale.
La structure do-catch et le mot-clé try
Pour gérer les erreurs potentielles, on utilise un bloc do-catch avec le mot-clé try avant l'appel :
do { try validatePassword("Hello123") print("Succès !")} catch PasswordError.tooShort { print("Erreur : mot de passe trop court")} catch PasswordError.missingDigit { print("Erreur : le mot de passe ne contient pas de chiffre")} catch PasswordError.missingUppercase { print("Erreur : le mot de passe ne contient pas de majuscule")} catch { print("Erreur inconnue : \\(error)")}Notez le dernier bloc catch — il intercepte toutes les erreurs non prises en compte précédemment. C'est une exigence obligatoire : le compilateur Swift vérifie que toutes les erreurs possibles sont traitées.
try? et try! — variantes simplifiées de gestion
Parfois, vous n'avez pas besoin d'un contrôle total sur les erreurs. Swift propose deux variantes abrégées :
- try? — convertit l'erreur en une valeur optionnelle
nil. S'il n'y a pas d'erreur, retourne le résultat enveloppé dans unOptional. - try! — affirme qu'il n'y aura pas d'erreur. Si une erreur survient, l'application se termine de manière inattendue (runtime crash).
// try? — ignorance sécurisée de l'erreurif let _ = try? validatePassword("weak") { print("Mot de passe validé")} else { print("Mot de passe non valide")}
// try! — uniquement si vous êtes sûr à 100 %let result = try! validatePassword("StrongPass1") // Crash si le mot de passe est invalideUtilisez try! uniquement dans des situations où l'erreur est théoriquement impossible (par exemple, lors du chargement d'une ressource intégrée dans le bundle de l'application).
Techniques avancées : rethrows, defer et Result
Relance des erreurs (rethrows)
Le mot-clé rethrows s'applique aux fonctions d'ordre supérieur qui acceptent une closure capable de lever une erreur. La fonction elle-même ne lève pas d'erreur, mais la transmet depuis la closure :
func processItems(_ items: [String], using validator: (String) throws -> Void) rethrows { for item in items { try validator(item) }}
// Utilisationdo { try processItems(["Hello", "World123"], using: validatePassword)} catch { print("Erreur de traitement : \\(error)")}Cela permet d'écrire des fonctions d'encapsulation flexibles sans dupliquer le code de gestion des erreurs.