ProgrammationDéveloppeur Swift

Qu'est-ce que defer en Swift, à quoi sert-il et quels sont les pièges à éviter ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Historique de la question :

defer a été introduit dans Swift pour une gestion plus pratique des ressources et l'exécution d'opérations après la fin d'un bloc de code, similaire à finally dans d'autres langages. Cette construction aide à montrer explicitement les étapes de nettoyage ou de finalisation du travail avec des ressources.

Problème :

De nombreux débutants pensent que defer exécute immédiatement le code imbriqué, ne comprenant pas toujours le moment de déclenchement. Il y a aussi des situations où plusieurs blocs defer peuvent être difficiles à comprendre sans connaître la règle LIFO (last-in, first-out). Des complications peuvent survenir avec try/catch et un retour prématuré.

Solution :

defer exécute le code imbriqué à la fin de la portée, avant de sortir du bloc de la fonction actuelle, même si la sortie de la fonction se produit plus tôt (via return, throw, break, etc.). Plusieurs defer s'exécutent dans l'ordre inverse de leur apparition.

Exemple de code :

func readFile() { print("Ouvrir le fichier") defer { print("Fermer le fichier") } print("Lire la ligne 1") if Bool.random() { print("Retour précoce !") return } print("Lire la ligne 2") } readFile() // Dans la console, il y aura toujours : Ouvrir le fichier, ..., Fermer le fichier (à la fin)

Caractéristiques clés :

  • defer s'active toujours lors de la sortie de la portée de la fonction/méthode
  • plusieurs defer fonctionnent selon le principe de la pile (LIFO)
  • s'active même lors d'un retour prématuré ou d'une erreur

Questions pièges.

Peut-on utiliser defer en dehors d'une fonction ?

Non, defer est autorisé uniquement à l'intérieur des fonctions, méthodes, initializers et deinitializers. Il ne peut pas être placé, par exemple, dans l'espace de noms global du fichier ou à l'intérieur d'une source de code en dehors des fonctions.

Que se passe-t-il avec defer s'il y a une exception (throw) dans le bloc ?

defer s'exécutera quand même. C'est l'un de ses avantages — la ressource est garantie d'être libérée même en cas d'erreur (throw). Cela met en œuvre le patron de libération sécurisée des ressources.

Dans quel ordre plusieurs defer s'exécutent-ils ?

Ils s'exécutent dans l'ordre inverse (LIFO) : le defer déclaré plus tard s'exécutera plus tôt.

Exemple de code :

func test() { defer { print("Premier") } defer { print("Deuxième") } print("Intérieur") } test() // Affichera : "Intérieur", "Deuxième", "Premier"

Erreurs courantes et anti-modèles

  • Utiliser defer pour du code où des retours/throws peuvent se produire, ce qui entraîne une confusion dans l'ordre d'exécution
  • Abuser de defer, rendant la lisibilité de la fonction difficile avec de nombreux blocs
  • Essayer d'utiliser defer en dehors de la portée de la fonction

Exemple de la vie réelle

Cas négatif

Une fonction avec plusieurs defer placés de manière non séquentielle ; nettoyage de certaines ressources omis, retour de la fonction à différents endroits. Cela conduit à des fuites de ressources et à un débogage difficile du comportement.

Avantages : Uniformité du code, les actions de nettoyage sont "rassemblées" au même endroit.

Inconvénients : Difficile de suivre ce qui sera exécuté et dans quel ordre ; des fuites peuvent survenir en raison d'erreurs de logique.

Cas positif

Un seul defer est fait pour chaque étape importante, placé exactement là où la ressource est initialisée, avec des commentaires. Revue de code vérifiée.

Avantages : Nettoyage garanti des ressources, compréhension claire de l'ordre des actions.

Inconvénients : Nécessite discipline et vigilance lors de l'ajout de nouvelles ressources et blocs de nettoyage.