didReceiveMemoryWarning, viewDidUnload y dealloc

Revisé muchas publicaciones, mis libros y Apple Developer y obtuve la mayor parte del conocimiento que necesito sobre el uso de estos. Estaría muy agradecido si alguna persona amable pudiera confirmar que lo hice bien (o corregirme) y también responder las dos preguntas.

Muchas gracias,

Chris.

Orden de mensajes Generalmente, los mensajes aparecerán en el siguiente orden:

  • RecibióMemoriaAdvertencia

  • viewDidUnload (que puede ser causado por 1): obviamente, solo se aplica a las clases de controladores de vista.

  • desalojar

RecibióMemoriaAdvertencia

Se llama cuando el sistema tiene poca memoria.

De forma predeterminada, los controladores de vista están registrados para notificaciones de advertencia de memoria y dentro del método de plantilla, la llamada a [super didReceiveMemoryWarning] libera la vista si no tiene una supervista, que es una forma de verificar si la vista es visible o no. Libera la vista estableciendo su propiedad en nil.

Acción: libere todo lo que no necesite, que probablemente esté deshaciendo lo que pudo haber configurado en viewDidLoad. No publique elementos de la interfaz de usuario, ya que viewDidUnload debería publicarlos.

Pregunta 1: parece que se llamará incluso si la vista es visible, por lo que es difícil ver lo que podría liberar de forma segura. Sería muy útil comprender esto y algunos ejemplos de lo que podría publicarse.

verDidDescargar

Se llama siempre que la propiedad View de un controlador de vista no visible se establece en nil, ya sea manualmente o más comúnmente a través de didReceiveMemoryWarning.

El método viewDidUnload está ahí para que pueda: - limpiar cualquier otra cosa que desee, para ahorrar memoria extra o - si ha retenido algunos IBOutlets, para ayudar a liberar memoria que de otro modo no se liberaría al descargar la vista .

Acción: en general, cualquier IBOutlet que publique en dealloc también debe publicarse (y las referencias se establecen en nil) en este método. Tenga en cuenta que si las propiedades están configuradas para conservar, establecerlas en nil también las liberará.

desalojar

Se llama cuando se desasigna el objeto del controlador de vista, que será cuando el recuento de retención caiga a cero.

Acción: libere todos los objetos que han sido retenidos por la clase, incluidas, entre otras, todas las propiedades con retención o copia.

Controladores de vista emergente y memoria

Pregunta 2: ¿Hacer estallar una vista la elimina de la memoria?

preguntado el 21 de febrero de 11 a las 15:02

Con respecto a la pregunta 2: ¿Te refieres a liberar una vista o sacar un controlador de vista desde un controlador de navegación? -

@Robin 0 abriendo el controlador de vista. -

4 Respuestas

Algunas correcciones y sugerencias:

  • didReceiveMemoryWarning prácticas

Como dijiste, la implementación predeterminada del controlador de didReceiveMemoryWarning publica su opinión si es 'seguro hacerlo'. Si bien no queda claro en los documentos de Apple qué significa 'seguro hacerlo', generalmente se reconoce que no tiene supervista (por lo tanto, no hay forma de que la vista sea visible actualmente), y loadView El método puede reconstruir la vista completa sin problemas.

La mejor práctica cuando anula didReceiveMemoryWarning es decir, no intentar liberar ningún objeto de vista en absoluto. Simplemente publique sus datos personalizados, si ya no son necesarios. Con respecto a las vistas, deje que la implementación de la superclase se ocupe de ellas.

A veces, sin embargo, la necesidad de los datos puede depender del estado de su vista. En la mayoría de los casos, esos datos personalizados se establecen en viewDidLoad método. En estos casos, "es seguro publicar datos personalizados" significa que sabe que loadView y viewDidLoad se invocará antes de que el controlador de vista vuelva a utilizar los datos personalizados.

Por lo tanto, en tu didReceiveMemoryWarning, llame primero a la implementación de la superclase y, si su vista está descargada, luego libere los datos personalizados porque sabe que loadView y viewDidLoad será invocado de nuevo con seguridad. Por ejemplo,

- (void)didReceiveMemoryWarning {
    /* This is the view controller's method */
    [super didReceiveMemoryWarning];
    if (![self isViewLoaded]) {
        /* release your custom data which will be rebuilt in loadView or viewDidLoad */
    }
}

Tenga cuidado de no utilizar self.view == nil, porque self.view asume que la vista es necesaria para alguien e inmediatamente cargará la vista nuevamente.

  • viewDidUnload Método

viewDidUnload se llama cuando el controlador de vista descargado la vista debido a una advertencia de memoria. Por ejemplo, si elimina la vista de la supervista y establece la view propiedad del controlador para nil, viewDidUnload el método será no ser invocado. Un punto sutil es que incluso si la vista de un controlador de vista ya está liberada y configurada como nula cuando el controlador recibe didReceiveMemoryWarning, por lo que en realidad no hay vista para descargar para el controlador, viewDidUnload se invocará si llama a la implementación de la superclase de didReceiveMemoryWarning.

Por eso no es una buena práctica configurar manualmente el view propiedad de un controlador de vista a cero. Si lo hace, es mejor que envíe un viewDidUnload mensaje también. Supongo que tu comprensión de viewDidUnload es más deseable, pero aparentemente no es el comportamiento actual.

  • Controladores de vista emergente

Si se refiere a "eliminar de la supervista" mediante "estallar", disminuye el recuento de retención de la vista, pero no necesariamente la desasigna.

Si se refiere a salir de un UINavigationController, en realidad disminuye el recuento de retención del controlador de vista en sí. Si el controlador de vista no es retenido por otro objeto, será desasignado, deseablemente con su vista. Como expliqué, viewDidUnloadno invocarse esta vez.

  • Otros...

Técnicamente, es posible que el recuento de retención no baje a cero. Es más probable que el objeto se desasigne sin establecer el recuento en cero de antemano.

Solo para asegurarse, el controlador de vista en sí normalmente no se desasigna por comportamientos predeterminados debido a la advertencia de memoria.

Respondido 21 Feb 11, 20:02

@MHC. Esto es genial, es realmente bueno tener una comprensión firme de esto y ahora ahora sé cómo distinguir las vistas que están ocultas. Estoy seguro de que esto ayudará a otros también. Gracias. - Chris

Si libero / configuro algunos datos en caché en nulo en didReceiveMemoryWarning, ¿debería hacerlo también en viewDidUnload? ¿Este último siempre sigue al primero? - Chris

Sí, viewDidUnload siempre sigue a didReceiveMemoryWarning. - MHC

¿Entonces no debería necesitar fijarlo en ambos? - Chris

No. Si espera que se invoque viewDidUnload, libere los datos allí. Una vez más, no se garantiza que viewDidUnload se invoque siempre que se descargue la vista, desafortunadamente. Si desea abordar el caso en el que otros pueden descargar la vista explícitamente, debe hacerlo en otro lugar. - MHC

RecibióMemoriaAdvertencia

...

Acción: libere todo lo que no necesite, que probablemente esté deshaciendo lo que pudo haber configurado en viewDidLoad.

Esto está mal. Todo lo que recreas en viewDidLoad debe liberarse (y establecerse en nil) en viewDidUnload. Como mencionas a continuación, didReceiveMemoryWarning también se llama cuando la vista es visible. En didReceiveMemoryWarning, debe liberar cosas como cachés u otros controladores de vista a los que se aferra que se puedan volver a crear de manera perezosa la próxima vez que se requieran (es decir, implementando su getter manualmente).

verDidDescargar

...

Acción: en general, cualquier IBOutlet que publique en dealloc también debe publicarse (y las referencias se establecen en nil) en este método. Tenga en cuenta que si las propiedades están configuradas para conservar, establecerlas en nil también las liberará.

Correcto. Generalmente, todo lo que crea en viewDidLoad y todos los IBOutlets que se declaran como retain debe liberarse y establecerse en nil aquí.

desalojar

...

Acción: libere todos los objetos que han sido retenidos por la clase, incluidas, entre otras, todas las propiedades con retención o copia.

Correcto. Vale la pena señalar que esto incluye todos los objetos que maneja en viewDidUnload porque este último no se llama implícitamente en el dealloc proceso (AFAIK, no del todo seguro). Por eso es esencial configurar todos los objetos de release en nil in viewDidUnload porque de lo contrario corre el riesgo de lanzar algo dos veces (primero en viewDidUnload, luego otra vez en dealloc; si establece el puntero en nil, la llamada de liberación en dealloc no tendrá ningún efecto).

Controladores de vista emergente y memoria

Pregunta 2: ¿Hacer estallar una vista la elimina de la memoria?

No necesariamente. Ese es un detalle de implementación que no debería preocuparle. Cualquiera que sea la práctica actual, Apple podría cambiarla en la próxima versión.

Respondido el 20 de junio de 20 a las 10:06

Gracias por las aclaraciones y correcciones. Ahora puedo limpiar mi código con confianza. - Chris

Solo para actualizar este hilo para que sea relevante para iOS6:

viewDidUnload y viewWillUnload quedaron obsoletos en iOS6. Estos métodos nunca se llaman.

Para conocer este y otros métodos obsoletos, consulte: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/DeprecationAppendix/AppendixADeprecatedAPI.html

Respondido 12 Abr '13, 12:04

Desde iOS 6 en adelante, cómo podemos verificar si la vista se cargó nuevamente. Dado que "viewDidUnload" está obsoleto. ¿Estás seguro de que "loadView" y "viewDidload" llamarán si la vista se elimina después de la advertencia "didReceiveMemoryWarning"?

Respondido el 14 de diciembre de 15 a las 12:12

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.