didReceiveMemoryWarning, viewDidUnload y dealloc
Frecuentes
Visto 12,189 veces
19
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?
4 Respuestas
31
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é, viewDidUnload
sí no 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
8
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
3
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
0
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 iphone memory-management uiviewcontroller or haz tu propia pregunta.
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
@Robin 0 abriendo el controlador de vista. - Chris