2009-01-29 17 views
5

Antecedentes:iPhone Desarrollo - Simular memoria Advertencia

tengo una aplicación de la barra de pestañas. Cada pestaña contiene un controlador de navegación que permite al usuario hacer la transición de una vista a la otra mostrando una información detallada de los datos (cada vista está siendo manejada por un controlador de vista y cada clase de controlador de vista tiene el método didReceiveMemoryWarning). Las listas se completan extrayendo los datos de los servicios web.

Problema:

Cuando yo uso "Hardware> Memoria Advertencia Simular" opción de iPhone Simulator, el método se llama didReceiveMemoryWarning para todos mis controladores de vista - incluso la que el usuario está viendo. No quiero borrar ningún contenido que esté siendo utilizado por el controlador de vista activo. ¿Cómo puedo lograr eso?

¿Qué método debe tener la implementación para volver a cargar los datos después de que se liberaron los datos debido a una advertencia de memoria? (Veo que las clases controlador de vista que contienen una vista de tabla llamada viewDidLoad método cuando el usuario vuelve a ese punto de vista, pero si la vista contiene (dicen UIWebView) entonces viewDidLoad método no se llama. ¿Por qué?)

editado (viernes 30 enero 2009 - 15:10)

. (Nota: estoy usando constructor de interfaz para la creación de puntos de vista, y loadView método está comentada)

Así, cuando un controlador de vista recibe una mensaje de advertencia de memoria, estos son los pasos que se llevan a cabo:

  1. método Después se llama:

    - (void)didReceiveMemoryWarning { 
        [super didReceiveMemoryWarning]; 
    } 
    
  2. Como resultado de la llamada a [super didReceiveMemoryWarning], [self setView:nil] llamada automáticamente?

  3. Si se deben borrar los recursos, se debe sobrescribir el método setView para borrar los recursos locales.

  4. [self setView:nil] no se llama si la vista está actualmente activa (De forma predeterminada). ¿Derecha? - Estoy realmente curioso qué método toma esta decisión y cómo?

Puede confirmar. Además, recibí un error al seguir este enfoque, pero al agregar myObject = nil después de liberar myObject en dealloc, el método de la clase controladora solucionó el problema. Gracias.

Respuesta

12

Ésta es una vieja pregunta, pero no veo una respuesta adecuada, así que aquí va:

Cuando se recibe una advertencia de memoria, -didReceiveMemoryWarning consigue llamar en todos los controladores de vista, si son el "actual" uno o no Los controladores de vista simplemente están escuchando la transmisión de eventos de advertencia de memoria.

Si la vista del controlador de la vista no se usa en el momento de la advertencia de memoria, el controlador la descargará estableciendo la propiedad en cero. ¿Cómo sabe si se usa la vista? Por la propiedad de la vista -superview. Si view.superview es nulo, la vista no es parte de ningún árbol y se puede descargar de forma segura.

Una vez que eso ocurre, se llama al controlador -viewDidUnload. Este es el lugar correcto para descargar los puntos de venta y todo lo que se volverá a crear en -viewDidLoad.


¿Para qué sirve -didReceiveMemoryWarning? Su controlador puede tener objetos que no se instancian hasta que se acceda. Por ejemplo, podría tener un controlador que a veces necesita una gran cantidad de datos de un archivo, pero no siempre. Usted podría tener un conjunto de propiedades de esta manera:

- (NSData*)bigChunkOfData { 
    // Get data from our instance variable _data, read from disk if necessary 
    if (_data == nil) { 
    _data = [[NSData alloc] initWithContentsOfFile:@"/path/to/data"]; 
    } 
    return _data; 
} 

Esto permitirá la lectura de los datos desde el disco esta primera vez, a continuación, guardarlo en una variable de instancia. Dado que la variable _data se crea bajo demanda, es seguro que la descarguemos en situaciones de poca memoria: se creará nuevamente la próxima vez que la necesitemos.

- (void)didReceiveMemoryWarning { 
    [super didReceiveMemoryWarning]; 

    [_data release]; 
    _data = nil; // <-- Very important: don't leave strong references dangling. 
} 
8

hago mi limpieza como esto:

-(void)setView:(UIView*)view 
{ 
    [super setView:view]; 
    if(view == nil) 
    { 
     // Our view has been cleared, therefore we should clean up everything 
     // we are not currently using 
.... 

setView:nil es llamado por UIViewController en respuesta a un aviso de memoria, si ese punto de vista no es visible en ese momento - que es básicamente lo que quiere saber.

EDITADO

En respuesta a los seguimientos:

  1. correcta.
  2. Eso es lo que hago, y funciona para mí.
  3. Correcto. La implementación de didReceiveMemoryWarning en UIViewController es lo que hace esto. Si no se sobreescribe didReceiveMemoryWarning, a continuación, la implementación de la clase base en UIViewController se llamará - si lo hace anularlo, obviamente, debe llamar:

    [super didReceiveMemoryWarning] 
    
+0

Incluso si yo no reemplazar el método didReceiveMemoryWarning, mi punto de vista se borra. ¿Porqué es eso? – Mustafa

+1

No anula significa que obtiene el comportamiento predeterminado implementado por UIViewController, que es borrar su vista. Si su anulación simplemente llama a la súper implementación, es lo mismo que no tener ninguna anulación en absoluto. –

1

En lo que respecta a las advertencias de control de la vista y de la memoria:

UIKit no solo permite la navegación desde un controlador de vista, sino que también permite la navegación a otros controladores de vista desde los existentes. En tal caso, se asignará un nuevo UIViewController y luego se cargará en la vista. El controlador de vista antiguo se apagará y se desactivará, pero aún posee muchos objetos, algunos en propiedades y variables personalizadas y otros en la propiedad/jerarquía de la vista. Y también lo hace el nuevo controlador de vista visible, con respecto a sus objetos de vista.

Debido a la cantidad limitada de memoria de los dispositivos móviles, tener dos juegos de objetos, uno en el controlador de visualización fuera de pantalla y otro en el controlador de visualización en pantalla, puede ser demasiado difícil de manejar. Si UIKit lo considera necesario, puede reclamar parte de la memoria del controlador de vista fuera de pantalla, que de todos modos no se muestra; UIKit sabe qué controlador de vista está en la pantalla y cuál está fuera de la pantalla, ya que, después de todo, es el que los está administrando (cuando llamas al presentModalViewController:animated: o dismissModalViewControllerAnimated:). Entonces, cada vez que se siente presionado, UIKit genera una advertencia de memoria, que descarga y libera su vista fuera de la pantalla desde la jerarquía de vista, luego llama a su método viewDidUnload personalizado para que haga lo mismo con sus propiedades y variables. UIKit libera self.view automáticamente, lo que nos permite liberar manualmente nuestras variables y propiedades en nuestro código viewDidUnload. Lo hace para todos los controladores de vista fuera de pantalla.

Cuando el sistema se está quedando sin memoria, se dispara un didReceiveMemoryWarning. Las vistas fuera de pantalla se recuperarán y se liberarán en la advertencia de memoria, pero su vista en pantalla no se liberará, es visible y necesaria. En caso de que su clase posea mucha memoria, como cachés, imágenes o similares, didReceiveMemoryWarning es donde debe purgarlos, incluso si están en pantalla; de lo contrario, su aplicación podría ser cancelada por exceso de recursos del sistema. Debe anular este método para asegurarse de que limpia su memoria; solo recuerda que llamas al [super didReceiveMemoryWarning];.

Una explicación aún más elaborada está disponible aquí: http://myok12.wordpress.com/2010/11/30/custom-uiviewcontrollers-their-views-and-their-memory-management/

0

Afortunadamente, el simulador tiene una práctica función que le permite poner en situaciones de poca memoria a prueba. Poner algunas declaraciones NSLog() tanto en viewDidLoad y didReceiveMemoryWarning, así: 

- (void)viewDidLoad { 
    NSLog(@"viewDidLoad"); 
    ... 
} 

- (void)didReceiveMemoryWarning { 
    NSLog(@"didReceiveMemoryWarning"); 
} 
Cuestiones relacionadas