Les closures en Swift sont des blocs de code autonomes qui peuvent capturer et conserver des références à des variables et des constantes du contexte environnant. Elles permettent d'organiser des callbacks, de gérer des traitements asynchrones et de stocker l'exécution de code en tant que valeurs de variables.
var counter = 0 let incrementer: () -> Void = { counter += 1 } incrementer() print(counter) // 1
[weak self], [unowned self]).self à l'intérieur de la closure.Quelle est la différence entre la capture forte et l'utilisation de
[weak self]ou[unowned self]dans la capture list d'une closure ? Quelles en sont les conséquences ?
Réponse :
Si vous ne spécifiez pas [weak self] ou [unowned self], la closure capturera par défaut self par référence forte, ce qui conduira à un cycle de rétention si la closure et self se référencent mutuellement. [weak self] capture self par référence faible (optional), [unowned self] par référence non contrôlée (non-optional). Un choix incorrect ou l'absence de capture list entraîne des fuites de mémoire ou des plantages.
class Test { var closure: (() -> Void)? func setup() { closure = { [weak self] in self?.doWork() } } func doWork() { ... } }
Histoire
Un programmeur n'a pas utilisé de capture list dans une closure à l'intérieur d'un UIViewController, qui lançait le chargement asynchrone de données. En conséquence, le contrôleur et sa vue n'étaient pas libérés, ce qui a entraîné une fuite de mémoire après la fermeture (dismiss). L'analyse de l'infrastructure a révélé des centaines de "contrôleurs suspendus" en mémoire.
Histoire
La closure a capturé self avec [unowned self], mais le cycle de vie de self s'est terminé avant celui de la closure. Cela a provoqué un crash lors de l'accès à un objet déjà libéré — l'application plantait lors de l'interaction avec self à l'intérieur de la closure.
Histoire
Dans le projet, à l'intérieur de closures imbriquées, deux variables ont été capturées : une par référence forte, l'autre par référence faible. Il s'est avéré que la référence faible était nulled trop tôt, et les données nécessaires au fonctionnement de la closure ont été perdues — le bug ne s'est manifesté que lors d'un stress-test en charge dans un environnement multithread.