Gestion des erreurs en Swift : blocs try/catch, throws et do-catch

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Gestion des erreurs en Swift : try/catch et au-delà



Le développement pour iOS et macOS nécessite une gestion fiable des erreurs. Swift fournit un mécanisme de gestion des défaillances puissant et élégant, basé sur les mots-clés throws, try, catch et do. Dans cet article, nous allons voir comment gérer correctement les erreurs, écrire du code lisible et éviter les pièges courants.



1. Les bases : le protocole Error et le mot-clé throws



Toute erreur en Swift doit être conforme au protocole Error. On utilise généralement des énumérations (enum) pour cela :



enum NetworkError: Error {    case badURL    case noData    case decodingFailed(String)}


Une fonction qui peut lever une erreur est marquée par le mot-clé throws :



func fetchUser(from urlString: String) throws -> User {    guard let url = URL(string: urlString) else {        throw NetworkError.badURL    }    // ... logique de la requête}


Désormais, lors de l'appel d'une telle fonction, le compilateur vous obligera à gérer l'erreur potentielle.



2. La structure do-catch : interception des erreurs



La manière la plus courante de gérer les erreurs est le bloc do-catch. Vous placez le code potentiellement dangereux dans do, et dans catch vous gérez la défaillance :



do {    let user = try fetchUser(from: "https://api.example.com/user")    print("Utilisateur chargé : \\(user.name)")} catch NetworkError.badURL {    print("URL invalide")} catch NetworkError.noData {    print("Le serveur n'a pas retourné de données")} catch NetworkError.decodingFailed(let message) {    print("Erreur de décodage : \\(message)")} catch {    print("Erreur inconnue : \\(error.localizedDescription)")}


Important : le dernier bloc catch sans type spécifique attrape toutes les erreurs restantes — il est conseillé de toujours l'ajouter.



2.1. Filtrage par motif dans catch



Vous pouvez utiliser des conditions plus complexes :



do {    let result = try riskyOperation()} catch let error as NetworkError where error == .badURL {    print("Problème avec l'URL")} catch {    print(error)}


3. Alternatives : try? et try!



Une gestion complète n'est pas toujours nécessaire. Swift propose deux approches simplifiées :



3.1. try? — valeur optionnelle



Si l'erreur n'est pas critique, vous pouvez convertir le résultat en optionnel. En cas d'échec, la fonction retournera nil :



let user = try? fetchUser(from: "https://example.com/user")// user est de type User? — nil en cas d'erreur


Idéal pour les situations où l'erreur peut simplement être ignorée (par exemple, le chargement d'un avatar).



3.2. try! — exécution forcée



Utilisez try! uniquement lorsque vous êtes absolument certain qu'il n'y aura pas d'erreur. Sinon, l'application plantera :



let user = try! fetchUser(from: "https://valid-url.com/user")// Si l'URL est invalide — l'application plantera


Appliquez try! dans les tests ou dans des situations où une défaillance est impossible selon la logique du programme.



4. Techniques avancées : rethrows et deferred



4.1. rethrows pour les fonctions d'ordre supérieur



Si votre fonction accepte une closure qui peut lever une erreur, utilisez rethrows. Cela permet de ne pas marquer votre propre fonction comme throws si la closure ne lève pas d'erreur :



func process(_ closure: () throws -> Void) rethrows {    try closure()}

// Appel sans closure throws — ne nécessite pas do-catchprocess { print("Sans erreurs") }

// Appel avec closure throws — nécessite une gestiontry process { throw NetworkError.noData }


4.2. deferred : nettoyage garanti



Le bloc defer s'exécute à la fin de toute fonction (succès ou erreur). Parfait pour fermer des fichiers ou libérer des ressources.

Blogs

Book Recommendations