KVO y ARC como eliminarObserver


87

¿Cómo se quita un observador de un objeto bajo ARC ? ¿Simplemente agregamos el observador y nos olvidamos de eliminarlo? Si ya no gestionamos la memoria de forma manual, ¿dónde renunciamos a observar?

Por ejemplo, en un controlador de vista:

[self.view addObserver:self
            forKeyPath:@"self.frame"
               options:NSKeyValueObservingOptionNew 
               context:nil];

Anteriormente, llamaría removeObserver:al deallocmétodo del controlador de vista .


4
Tenga en cuenta que es una muy mala idea para KVO .frame. Como lo escribieron los ingenieros de Apple en StackOverflow, la propiedad de marco de UIKit no es compatible con KVO. Cuando funciona, es solo por pura casualidad.
steipete

2
¿No debería ser su keyPath en @"frame"lugar de @"self.frame"?
Besi

Respuestas:


126

Aún puede implementar -deallocbajo ARC, que parece ser el lugar apropiado para eliminar la observación de valores clave. Simplemente ya no llamas [super dealloc]desde este método.

Si -releaseantes anulabas , estabas haciendo las cosas de forma incorrecta.


1
¿Estas seguro acerca de esto? Cito de clang.llvm.org/docs/… , sección 7.1.2. dealloc: "Justificación: aunque ARC destruye las variables de instancia automáticamente, todavía existen razones legítimas para escribir un método dealloc, como liberar recursos no retenibles. No llamar a [super dealloc] en un método de este tipo es casi siempre un error".
Elise van Looij

@ElisevanLooij Sí, eso es cierto. Si se deriva de esta clase, parece obvio que debe llamar [super dealloc]. ¿Quién más debería hacer esto por ti?
Björn Landmesser

@ElisevanLooij Vaya, bueno, debería haberlo comprobado antes. No está permitido llamar [super dealloc]a un método dealloc. No tengo idea de cómo funcionaría esto entonces al subclasificar la clase mencionada. Tal vez sea recomendable usar finalizeen su lugar (donde llame [super finalize])
Björn Landmesser

17
@ElisevanLooij - El punto que estaban tratando de hacer es con respecto al caso de administración de memoria manual. Debido a que no llamar al [super dealloc]último en ese método es casi siempre un error en la administración de memoria manual, el compilador lo maneja por usted ahora, por lo que ya no puede llamar -deallocdirectamente. Lo único que coloca en un -deallocmétodo en ARC son los recursos que no son objetos que necesita liberar o tareas de limpieza como eliminar observadores. La redacción que usan es un poco turbia, pero esto es lo que querían decir.
Brad Larson

7
@ BjörnMilcke: como comento en la respuesta de Elise, -finalizese usa para esto en la recolección de basura, donde -deallocnunca se llama, pero es perfectamente aceptable colocar este código en -deallocARC. [super dealloc]se llama automáticamente, por lo que es un error llamarlo bajo ARC.
Brad Larson

1

Lo hago con este codigo

- (void)dealloc
{
@try{
    [self.uAvatarImage removeObserver:self forKeyPath:@"image" context:nil];
} @catch(id anException) {
    //do nothing, obviously it wasn't attached because an exception was thrown
}
}    

2
¿Cuál es el objetivo del manejo de excepciones dealloc? Es demasiado tarde para hacer algo al respecto.
Abizern

¿Cuál es el punto de eliminar observadores en una variable de instancia en dealloc? Esta uAvatarImage se desasignará pronto junto con cualquier observador que se haya suscrito a sus rutas clave.
shoumikhin

1
@shoumikhin Estoy usando ARC y tuve que eliminar el observador en el método dealloc. Tengo la misma pregunta que tú. Sin embargo, cuando ejecuté varias instancias de la clase, finalmente obtuve el error exc_bad_address. Hacer esto resolvió el problema. Además, la respuesta de aquí stackoverflow.com/questions/32490808/… me ayudó a descubrir el problema.
mac10688

-2

En otra parte del desbordamiento de pila, Chris Hanson aconseja utilizar el método de finalización para este propósito e implementar un método de invalidación separado para que los propietarios puedan decirles a los objetos que están listos. En el pasado, encontré que las soluciones de Hanson estaban bien pensadas, así que seguiré con eso.


13
Tenga en cuenta que se refería a la recolección de basura allí, no a ARC (su respuesta fue escrita en 2008). Bajo recolección de basura, -deallocnunca se llama. En ARC, lo es. Es perfectamente aceptable eliminar a los observadores de KVO -dealloc, como indica Chris Lattner (quién sabe de qué está hablando) en los foros de desarrolladores de Apple aquí: devforums.apple.com/message/475850
Brad Larson

3
Gracias Brad, por hacer todo este trabajo. No para finalizar, sí para deslocalizar pero sin [super desbloqueo]. Realmente simple, una vez que lo sabes. ¡Oye, @drunknbass, acepta la respuesta de ese hombre!
Elise van Looij
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.