dealloc en Swift

145

Me gustaría realizar una limpieza al final de la vida útil de un controlador de vista, es decir, eliminar una NSNotificationCenternotificación. La implementación de deallocresultados en un error del compilador Swift:

Cannot override 'dealloc' which has been marked unavailable

¿Cuál es la forma preferida de realizar una limpieza al final de la vida de un objeto en Swift?

Kyle Clegg
fuente

Respuestas:

333
deinit {
    // perform the deinitialization
}

De la documentación de Swift :

Se llama a un desinicializador inmediatamente antes de que se desasigne una instancia de clase. Usted escribe desinicializadores con la palabra clave deinit, de forma similar a cómo se escriben los inicializadores con la palabra clave init. Los desinfectantes solo están disponibles en los tipos de clase.

Por lo general, no necesita realizar una limpieza manual cuando sus instancias se desasignan. Sin embargo, cuando trabaje con sus propios recursos, es posible que deba realizar una limpieza adicional usted mismo. Por ejemplo, si crea una clase personalizada para abrir un archivo y le escribe algunos datos, es posible que deba cerrar el archivo antes de que se desasigne la instancia de la clase.

Kyle Clegg
fuente
45
deinit {
    // perform the deinitialization
}

es la respuesta correcta para Swift "dealloc".

Sin embargo, es bueno señalar nuevo en iOS 9 que NSNotificationCenter ya no necesita ser limpiado.

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

NSNotificationCenter

En OS X 10.11 e iOS 9.0, NSNotificationCenter y NSDistributedNotificationCenter ya no enviarán notificaciones a los observadores registrados que puedan ser desasigados. Si el observador puede almacenarse como una referencia débil a cero, el almacenamiento subyacente almacenará al observador como una referencia débil a cero, alternativamente si el objeto no puede almacenarse débilmente (es decir, tiene un mecanismo personalizado de retención / liberación que evitaría el tiempo de ejecución de poder almacenar el objeto débilmente) almacenará el objeto como una referencia de puesta a cero no débil. Esto significa que los observadores no están obligados a anular el registro en su método de desasignación. La próxima notificación que se enrutará a ese observador detectará la referencia puesta a cero y automáticamente anulará el registro del observador. Si se puede hacer referencia débil a un objeto, las notificaciones ya no se enviarán al observador durante la desasignación; El comportamiento anterior de recibir notificaciones durante el Dealloc todavía está presente en el caso de los observadores de referencia de puesta a cero no débil. Los observadores basados ​​en bloques a través del método - [NSNotificationCenter addObserverForName: object: queue: usingBlock] aún no deben registrarse cuando ya no estén en uso, ya que el sistema todavía tiene una fuerte referencia a estos observadores. La eliminación prematura de observadores (ya sea débilmente referenciada o referenciada a cero) todavía es compatible. CFNotificationCenterAddObserver no se ajusta a este comportamiento ya que el observador puede no ser un objeto. Los observadores basados ​​en bloques a través del método - [NSNotificationCenter addObserverForName: object: queue: usingBlock] aún no deben registrarse cuando ya no estén en uso, ya que el sistema todavía tiene una fuerte referencia a estos observadores. La eliminación prematura de observadores (ya sea débilmente referenciada o referenciada a cero) todavía es compatible. CFNotificationCenterAddObserver no se ajusta a este comportamiento ya que el observador puede no ser un objeto. Los observadores basados ​​en bloques a través del método - [NSNotificationCenter addObserverForName: object: queue: usingBlock] aún no deben registrarse cuando ya no estén en uso, ya que el sistema todavía tiene una fuerte referencia a estos observadores. La eliminación prematura de observadores (ya sea débilmente referenciada o referenciada a cero) todavía es compatible. CFNotificationCenterAddObserver no se ajusta a este comportamiento ya que el observador puede no ser un objeto.

pero tenga en cuenta los puntos a continuación sobre referencias fuertes, por lo que es posible que deba preocuparse por la limpieza de todos modos ...

James
fuente
3
A menos que el bloque de notificación tenga una referencia fuerte, debe eliminar al observador.
TigerCoding
+1 por no tener que limpiar a los observadores. ¡Importante saber! Hago que todas las referencias de captura sean débiles, así que nunca tengo que lidiar con esto.
n13
2
Los bloques de notificación siempre parecen estar fuertemente referenciados de acuerdo con la documentación. Por lo tanto: Si está utilizando bloques de manejar sus notificaciones que tiene para anular el registro de ellos dentro de deinit.
marsbear
22

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

Swift desasigna automáticamente sus instancias cuando ya no son necesarias, para liberar recursos. Swift maneja la gestión de memoria de instancias a través del conteo automático de referencias (ARC), como se describe en Conteo automático de referencias. Por lo general, no necesita realizar una limpieza manual cuando sus instancias se desasignan. Sin embargo, cuando trabaje con sus propios recursos, es posible que deba realizar una limpieza adicional usted mismo. Por ejemplo, si crea una clase personalizada para abrir un archivo y le escribe algunos datos, es posible que deba cerrar el archivo antes de que se desasigne la instancia de la clase.

Las definiciones de clase pueden tener como máximo un desinfectante por clase. El desinfectante no toma ningún parámetro y se escribe sin paréntesis:

deinit {
    // perform the deinitialization
}
Varsha Vijayvargiya
fuente
2

Se requiere eliminar el observador antes de la desasignación; de lo contrario, se produciría un bloqueo. Se puede hacer usando

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

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

}
Espía
fuente
-2

Tenga cuidado al llamar a un método en otra clase desde deinit , probablemente terminará en bloqueo

Jeba Moses
fuente
1
Votado como ese no necesariamente debería ser el caso. De ref. docs : debido a que una instancia no se desasigna hasta después de que se llama a su desinicializador, un desinicializador puede acceder a todas las propiedades de la instancia a la que se llama y puede modificar su comportamiento en función de esas propiedades (como buscar el nombre de un archivo que necesita estar cerrado).
superjos