dealloc à Swift

145

Je voudrais effectuer un nettoyage à la fin de la vie d'un contrôleur de vue, à savoir pour supprimer une NSNotificationCenternotification. L'implémentation deallocentraîne une erreur du compilateur Swift:

Cannot override 'dealloc' which has been marked unavailable

Quelle est la meilleure façon d'effectuer un nettoyage à la fin de la vie d'un objet dans Swift?

Kyle Clegg
la source

Réponses:

333
deinit {
    // perform the deinitialization
}

À partir de la documentation Swift :

Un désinitialiseur est appelé immédiatement avant qu'une instance de classe ne soit libérée. Vous écrivez des désinitialiseurs avec le mot-clé deinit, de la même manière que les initiateurs sont écrits avec le mot-clé init. Les déinitialiseurs ne sont disponibles que sur les types de classe.

En règle générale, vous n'avez pas besoin d'effectuer un nettoyage manuel lorsque vos instances sont désallouées. Cependant, lorsque vous travaillez avec vos propres ressources, vous devrez peut-être effectuer vous-même un nettoyage supplémentaire. Par exemple, si vous créez une classe personnalisée pour ouvrir un fichier et y écrire des données, vous devrez peut-être fermer le fichier avant que l'instance de classe ne soit libérée.

Kyle Clegg
la source
45
deinit {
    // perform the deinitialization
}

est la bonne réponse pour Swift "dealloc".

Cependant, il est bon de souligner les nouveautés d'iOS 9 que NSNotificationCenter n'a plus besoin d'être nettoyé!

https://developer.apple.com/library/content/releasenotes/Foundation/RN-FoundationOlderNotes/index.html#X10_11Notes

NSNotificationCenter

Sous OS X 10.11 et iOS 9.0, NSNotificationCenter et NSDistributedNotificationCenter n'enverront plus de notifications aux observateurs enregistrés susceptibles d'être désalloués. Si l'observateur peut être stocké en tant que référence faible à zéro, le stockage sous-jacent stockera l'observateur en tant que référence faible à zéro, ou si l'objet ne peut pas être stocké faiblement (c'est-à-dire qu'il a un mécanisme de conservation / libération personnalisé qui empêcherait l'exécution de pouvoir stocker l'objet faiblement), il stockera l'objet en tant que référence de mise à zéro non faible. Cela signifie que les observateurs ne sont pas obligés de se désinscrire dans leur méthode de désallocation. La prochaine notification qui serait acheminée vers cet observateur détectera la référence remise à zéro et désenregistrera automatiquement l'observateur. Si un objet peut être faiblement référencé, les notifications ne seront plus envoyées à l'observateur lors de la désallocation; le comportement antérieur de réception des notifications pendant la désallocation est toujours présent dans le cas des observateurs de référence à zéro non-faible. Les observateurs basés sur des blocs via la méthode - [NSNotificationCenter addObserverForName: object: queue: usingBlock] doivent toujours être désenregistrés lorsqu'ils ne sont plus utilisés car le système contient toujours une référence forte à ces observateurs. La suppression prématurée d'observateurs (faiblement référencés ou référencés à zéro) est toujours prise en charge. CFNotificationCenterAddObserver n'est pas conforme à ce comportement car l'observateur n'est peut-être pas un objet. Les observateurs basés sur des blocs via la méthode - [NSNotificationCenter addObserverForName: object: queue: usingBlock] doivent toujours être désenregistrés lorsqu'ils ne sont plus utilisés car le système contient toujours une référence forte à ces observateurs. La suppression prématurée d'observateurs (faiblement référencés ou référencés à zéro) est toujours prise en charge. CFNotificationCenterAddObserver n'est pas conforme à ce comportement car l'observateur n'est peut-être pas un objet. Les observateurs basés sur des blocs via la méthode - [NSNotificationCenter addObserverForName: object: queue: usingBlock] doivent toujours être désenregistrés lorsqu'ils ne sont plus utilisés car le système contient toujours une référence forte à ces observateurs. La suppression prématurée d'observateurs (faiblement référencés ou référencés à zéro) est toujours prise en charge. CFNotificationCenterAddObserver n'est pas conforme à ce comportement car l'observateur n'est peut-être pas un objet.

mais notez les points ci-dessous concernant les références fortes, vous devrez peut-être vous soucier du nettoyage de toute façon ...?

James
la source
3
À moins que le bloc de notification n'ait une référence forte, vous devez supprimer l'observateur.
TigerCoding
+1 pour ne pas avoir à nettoyer les observateurs. Important à savoir! Je rend toutes les références de capture faibles, donc je n'ai jamais à m'occuper de cela.
n13
2
Les blocs de notification semblent toujours être fortement référencés selon la documentation. Donc: si vous utilisez des blocs pour gérer vos notifications, vous devez vous désinscrire à l'intérieur de deinit.
marsbear
22

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Deinitialization.html

Swift désalloue automatiquement vos instances lorsqu'elles ne sont plus nécessaires, pour libérer des ressources. Swift gère la gestion de la mémoire des instances via le comptage automatique des références (ARC), comme décrit dans Comptage automatique des références. En règle générale, vous n'avez pas besoin d'effectuer un nettoyage manuel lorsque vos instances sont désallouées. Cependant, lorsque vous travaillez avec vos propres ressources, vous devrez peut-être effectuer vous-même un nettoyage supplémentaire. Par exemple, si vous créez une classe personnalisée pour ouvrir un fichier et y écrire des données, vous devrez peut-être fermer le fichier avant que l'instance de classe ne soit libérée.

Les définitions de classe peuvent avoir au plus un désinitialiseur par classe. Le déinitialiseur ne prend aucun paramètre et est écrit sans parenthèses:

deinit {
    // perform the deinitialization
}
Varsha Vijayvargiya
la source
2

la suppression de l'observateur est requise avant la désallocation sinon un crash se produirait. Cela peut être fait en utilisant

deinit {
    // perform the deinitialization
    print("deinit")

    removeObserver(self, forKeyPath: kSelectedViewControllerKey, context: nil)
    removeObserver(self, forKeyPath: kSelectedIndexKey, context: nil)

}
Spydy
la source
-2

Soyez prudent lorsque vous appelez une méthode dans une autre classe depuis deinit, elle finira probablement par planter

Jeba Moïse
la source
1
Évalué car cela ne devrait pas nécessairement être le cas. De la réf. docs : comme une instance n'est pas désallouée tant que son désinitialiseur n'a pas été appelé, un désinitialiseur peut accéder à toutes les propriétés de l'instance sur laquelle il est appelé et peut modifier son comportement en fonction de ces propriétés (comme rechercher le nom d'un fichier qui doit sois fermé).
superjos