Le dilemme éternel : mettre [unowned self] ou pas ?
\n\nSi vous avez déjà programmé en Swift et rencontré les closures, vous vous êtes sûrement demandé : « Dois-je écrire [unowned self] dans chaque closure où j’utilise self ? ».
C’est l’une des questions les plus populaires sur Stack Overflow (des dizaines de milliers de vues), et pour cause. En 2025, avec l’arrivée de nouvelles fonctionnalités Swift (comme un analyseur de cycle de vie amélioré et des vérifications plus strictes du compilateur), la réponse est devenue encore plus nuancée.
\n\nDans cet article, nous ne donnons pas simplement une réponse sèche « oui » ou « non ». Nous analysons comment fonctionne réellement la gestion de la mémoire en Swift, quand [unowned self] est une bouée de sauvetage et quand c’est une bombe à retardement, et quelles sont les meilleures pratiques à utiliser dans les projets modernes.
C’est parti ! 🚀
\n\nBref aperçu de l’ARC et des cycles de rétention (pour les débutants)
\n\nAvant de parler de [unowned self], rappelons comment fonctionne l’Automatic Reference Counting (ARC).
L’ARC est un mécanisme de comptage de références. Chaque objet en Swift (instance d’une classe) possède un compteur de références. Lorsque vous créez une nouvelle référence vers un objet (par exemple, en l’affectant à une propriété ou en le mettant dans un tableau), le compteur augmente. Lorsque la référence disparaît, il diminue. Lorsque le compteur atteint zéro, l’objet est détruit.
\n\nLe problème survient lorsque deux objets se référencent mutuellement (référence cyclique). Imaginez :
\n\nclass Parent {\n var child: Child?\n}\n\nclass Child {\n var parent: Parent? // Référence forte vers Parent\n}\n\nSi vous créez une paire Parent et Child et définissez les deux références, ils se retiendront mutuellement pour toujours. L’ARC ne mettra jamais leurs compteurs à zéro. C’est ce qu’on appelle un cycle de rétention (retain cycle).
Les closures sont aussi des types par référence. Lorsqu’une closure capture self (par exemple, pour appeler une méthode), elle stocke une référence forte vers l’objet. Si l’objet, à son tour, stocke une référence forte vers la closure (par exemple, comme propriété), le même cycle se produit.
Weak vs Unowned : quelle est la différence ?
\n\nPour briser le cycle, nous utilisons weak ou unowned.
weak self
\n- \n
- Toujours optionnel (
self?). \n - La référence n’augmente pas le compteur ARC. \n
- Lorsque l’objet est détruit, la référence
weakdevient automatiquementnil. \n - Sûr — vous vérifiez toujours
guard let self = self else { return }. \n
unowned self
\n- \n
- Non optionnel (
selfsans point d’interrogation). \n - La référence n’augmente pas le compteur ARC. \n
- Lorsque l’objet est détruit, la référence
unownedne devient pas nil. Elle devient une référence pendante (dangling pointer). \n - L’accès à une telle référence après la destruction de l’objet provoque un crash (EXC_BAD_ACCESS). \n
Point clé : unowned est une promesse faite au compilateur : « Je garantis que l’objet sera vivant tant que cette closure s’exécute ». Si vous vous trompez, l’application plante.
Quand utiliser [unowned self] (et quand ne pas le faire)
\n\nAnalysons des scénarios réels de la pratique du développement iOS en 2025.
\n\nCas 1 : [unowned self] est OK (et même préférable)
\n\nUtilisez [unowned self] lorsque vous êtes absolument certain que self sera vivant au moment de l’exécution de la closure. Un exemple typique est une closure qui s’exécute de manière synchrone à l’intérieur d’une méthode de l’objet, et où l’objet est garanti de ne pas être détruit avant la fin de la closure.
class DataFetcher {\n var data: Data?\n \n func fetchData() {\n // Cette closure s’exécute de manière synchrone à l’intérieur de la méthode\n let processCl