defer est une construction spéciale de Swift qui permet d'exécuter un certain bloc de code juste avant de quitter la portée (scope) d'une fonction, que ce soit par un retour normal ou en cas d'erreur (throw). Defer est pratique pour libérer des ressources, annuler des modifications ou finaliser des opérations.
Particularités de fonctionnement :
Exemple :
func testDefer() { print("begin") defer { print("first defer") } defer { print("second defer") } print("end") } // Affichera : // begin // end // second defer // first defer
Cas limites :
Tous les blocs defer dans la fonction seront-ils exécutés si fatalError est appelé à l'intérieur ?
Réponse : Non, si un fatalError (ou un crash incontrôlable similaire) est appelé dans la fonction, tous les blocs defer différés ne seront pas exécutés. defer ne garantit pas l'exécution du code en cas d'arrêt brutal de l'application.
Exemple :
func foo() { defer { print("Defer 1") } fatalError("Oops") defer { print("Defer 2") } } foo() // n'affichera rien, une panne se produira
Histoire
Dans le projet, nous avons utilisé defer pour fermer un descripteur de fichier. En cas d'erreur, nous avons utilisé fatalError au lieu d'un throw correct, ce qui entraînait une fuite de ressource ouverte, car defer ne s'exécutait pas lors d'un crash.
Histoire
Dans une fonction, il y avait plusieurs defer, dont certains dépendaient de l'état des variables locales. Le développeur s'attendait à ce qu'une variable soit égale à une valeur spécifique, mais cette valeur a changé dans le defer par un autre morceau de code, et au moment de l'exécution du defer, la valeur actuelle, et non l'ancienne, a été utilisée, entraînant un bug lors de l'annulation de la transaction avec l'ID incorrect.
Histoire
Dans un closure imbriqué, nous avons écrit un bloc defer, pensant qu'il s'exécuterait lors de la sortie de la fonction externe. En conséquence, ce defer s'est exécuté à la sortie du closure, et non de la fonction entière, et la ressource a été libérée trop tôt.