Pregunta ¿Cómo eliminas KVO de una propiedad débil?


Tengo una vista (llamaremos a esta vista A) que tiene una weak propiedad a su supervista (ver B). Ver la vista superior de A KVO, vista B. Dado que la referencia de la vista A para ver B es una propiedad débil (para evitar un ciclo de retención), ¿cómo puedo eliminar al observador (A observando a B)? Ver la referencia de A para ver B se anula antes de que tenga la oportunidad de eliminarlo.

A sobrevive B ya que el controlador de vista tiene una fuerte referencia a A. Aquí está el mensaje de registro con fugas:

An instance 0x9ac5200 of class UITableView was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object. Set a breakpoint on NSKVODeallocateBreak to stop here in the debugger. Here's the current observation info:
<NSKeyValueObservationInfo 0x8660360> (
<NSKeyValueObservance 0x8660320: Observer: 0x8660020, Key path: contentOffset, Options: <New: YES, Old: NO, Prior: NO> Context: 0x8660020, Property: 0x864ac80>
)

B es una UITableView. Establecer un punto de interrupción en NSKVODeallocateBreak produce resultados inútiles.

En A's removeFromSuperview, Trato de eliminar al observador, pero la referencia de A a B ya es nil.

Cambiar a unsafe_unretained y hacer las cosas más manualmente o llamando [A removeFromSuperview] en la vista del controlador dealloc resuelve el problema Me gustaría saber cómo resolver esto usando un weak propiedad sin embargo.

Aquí está el código relevante: https://gist.github.com/2822776


35
2018-05-29 04:48


origen


Respuestas:


Encuentro que cualquier tipo de código requerido especialmente para este caso es realmente innecesario ya que la eliminación puede ser automática.

Con la introducción de ARC, Apple debería haber proporcionado la eliminación automática de observadores que solucionaría casos como este, pero desafortunadamente no lo hicieron. Pero hice mi propia categoría que agrega esta característica deficiente: https://github.com/krzysztofzablocki/SFObservers Le expliqué cómo lo hice en mi blog: http://www.merowing.info/2012/03/automatic-removal-of-nsnotificationcenter-or-kvo-observers/

Si miras mi solución, notarás que se asegura de que se invoque el código original, incluso si uno de los métodos llama a otros, de modo que incluso si Apple cambia su comportamiento interno, la categoría seguirá funcionando bien :)


2
2018-05-29 10:28



Podría definir una propiedad débil explícita que haga referencia a la supervista y luego observar self con una ruta clave como @"propertyReferringSuperview.propertyOfSuperview"? Cuando recibe una notificación de KVO, verifica si self.propertyReferringSuperview == nil y deja de observar @"propertyReferringSuperview.propertyOfSuperview".


1
2018-05-29 09:15



En lugar de agregar una propiedad débil, podrías usar el superview propiedad e implementación willMoveToSuperview: para agregar / eliminar la observación KVO.

- (void)willMoveToSuperview:(UIView *)newSuperview {
    [self.superview removeObserver:self forKeyPath:@"contentOffset" context:context];
    [newSuperview addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:context];
    [super willMoveToSuperview:newSuperview]; // optional as default implementation does nothing
}

0
2018-05-29 10:33