12

Estoy confundido sobre por qué el observador nunca se elimina en el siguiente código. En mi viewDidAppear Tengo el siguiente:¿Por qué no eliminar Observer de NSNotificationCenter: addObserverForName: usingBlock get called

-(void)viewDidAppear:(BOOL)animated{ 

id gpsObserver = [[NSNotificationCenter defaultCenter] 
          addObserverForName:FI_NOTES[kNotificationsGPSUpdated] 
          object:nil 
          queue:[NSOperationQueue mainQueue] 
          usingBlock:^(NSNotification *note){ 

           NSLog(@"run once, and only once!"); 

       [[NSNotificationCenter defaultCenter] removeObserver:gpsObserver]; 

     }]; 

} 

El observador nunca se elimina y el comunicado se emite cada vez que la notificación se envía. ¿Alguien puede proporcionar alguna orientación?

Respuesta

28

Cuando el bloque se inserta en la pila por addObserverForName:, el método aún no ha regresado, por lo que gpsObserver es nulo (en ARC) o basura/indefinido (no en ARC). Declare la variable usando __block afuera y esto debería funcionar.

__block __weak id gpsObserver; 

gpsObserver = [[NSNotificationCenter defaultCenter] 
          addObserverForName:FI_NOTES[kNotificationsGPSUpdated] 
          object:nil 
          queue:[NSOperationQueue mainQueue] 
          usingBlock:^(NSNotification *note){ 

           NSLog(@"run once, and only once!"); 

       [[NSNotificationCenter defaultCenter] removeObserver:gpsObserver]; 

     }]; 

He añadido un __weak para asegurar que no haya pérdida de memoria (según la respuesta de Matt). Código no probado.

+0

Eso tiene sentido y funciona como se esperaba; Gracias por tu ayuda. – warpedspeed

11

Encuentro que de hecho hay una pérdida de memoria a menos que el observador esté marcado __block y __weak. Use los instrumentos para asegurarse de que self no esté siendo retenido; Apuesto a que es. Esto, sin embargo, funciona correctamente (desde mi código real):

__block __weak id observer = [[NSNotificationCenter defaultCenter] 
    addObserverForName:@"MyMandelbrotOperationFinished" 
    object:op queue:[NSOperationQueue mainQueue] 
    usingBlock:^(NSNotification *note) { 
     // ... do stuff ... 
     [[NSNotificationCenter defaultCenter] 
      removeObserver:observer 
      name:@"MyMandelbrotOperationFinished" 
      object:op]; 
}]; 
+0

Me encantaría que introdujeran el método equivalente que en realidad no requeriría que persistiera en los observadores, sino que se usara como uno, simplemente usando bloques en lugar de selectores. – Eugene

+2

No necesita hacer 'observer'' __weak' si lo establece en 'nil' después de eliminarlo de' NSNotificationCenter'. Lo he comprobado con Instruments. –

+0

Este es un buen pedazo de código, señor. – Andy

Cuestiones relacionadas