objective c - infusion - ¿Cómo puedo saber si un objeto tiene un observador clave de valor adjunto
kvo español (10)
Además de la respuesta de Adam, me gustaría sugerir utilizar macro como esta
#define SafeRemoveObserver(sender, observer, keyPath) /
@try{/
[sender removeObserver:observer forKeyPath:keyPath];/
}@catch(id anException){/
}
ejemplo de uso
- (void)dealloc {
SafeRemoveObserver(someObject, self, somePath);
}
si le dices a un objeto objetivo c que elimine Observers: para una ruta clave y esa ruta clave no se ha registrado, rompe los sads. me gusta -
''No se puede eliminar a un observador de la ruta clave'' theKeyPath ''porque no está registrado como observador''.
hay una manera de determinar si un objeto tiene un observador registrado, entonces puedo hacer esto
if (object has observer){
remove observer
}
else{
go on my merry way
}
Cuando agrega un observador a un objeto, puede agregarlo a un NSMutableArray
como este:
- (void)addObservedObject:(id)object {
if (![_observedObjects containsObject:object]) {
[_observedObjects addObject:object];
}
}
Si quiere observar los objetos, puede hacer algo como:
for (id object in _observedObjects) {
if ([object isKindOfClass:[MyClass class]]) {
MyClass *myObject = (MyClass *)object;
[self unobserveMethod:myObject];
}
}
[_observedObjects removeAllObjects];
Recuerde, si no observa un solo objeto, elimínelo de la matriz _observedObjects
:
- (void)removeObservedObject:(id)object {
if ([_observedObjects containsObject:object]) {
[_observedObjects removeObject:object];
}
}
El objetivo del patrón del observador es permitir que una clase observada sea "sellada", para no saber o preocuparse de si se está observando. Está explícitamente tratando de romper este patrón.
¿Por qué?
El problema que tienes es que estás asumiendo que te están observando cuando no lo estás. Este objeto no comenzó la observación. Si desea que su clase tenga control de este proceso, debe considerar usar el centro de notificaciones. De esta forma, tu clase tiene control total sobre cuándo se pueden observar los datos. Por lo tanto, no le importa quién está mirando.
En mi opinión, esto funciona de manera similar al mecanismo retainCount. No puede estar seguro de que en el momento actual tenga a su observador. Incluso si marca : self.observationInfo - no puede estar seguro de que tendrá / no tendrá observadores en el futuro.
Como retenerCount . Tal vez el método observationInfo no es exactamente ese tipo de inútil, pero solo lo uso en depuración.
Como resultado, solo tienes que hacerlo como en la gestión de memoria. Si agregó un observador, simplemente quítelo cuando no lo necesite. Como usar los métodos viewWillAppear / viewWillDisappear etc. P.ej:
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self addObserver:nil forKeyPath:@"" options:NSKeyValueObservingOptionNew context:nil];
}
-(void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self removeObserver:nil forKeyPath:@""];
}
Y necesita algunas comprobaciones específicas: implemente su propia clase que maneja una serie de observadores y úsela para sus comprobaciones.
FWIW, [someObject observationInfo]
parece ser nil
si someObject
no tiene ningún observador. Sin embargo, no confiaría en este comportamiento, ya que no lo he visto documentado. Además, no sé cómo leer observationInfo
para obtener observadores específicos.
Intenta capturar tu llamada removeObserver
@try{
[someObject removeObserver:someObserver forKeyPath:somePath];
}@catch(id anException){
//do nothing, obviously it wasn''t attached because an exception was thrown
}
La única forma de hacerlo es establecer una bandera cuando agrega un observador.
La verdadera pregunta es por qué no sabes si lo estás observando o no.
Si estás haciendo esto en la clase del objeto observado, detente. Lo que sea que esté observando espera seguir observándolo. Si cortó las notificaciones del observador sin su conocimiento, espera que las cosas se rompan; más específicamente, se espera que el estado del observador se quede obsoleto ya que no recibe actualizaciones del objeto observado anteriormente.
Si estás haciendo esto en la clase del objeto de observación, simplemente recuerda qué objetos estás observando (o, si solo observas un objeto, si lo estás observando). Esto supone que la observación es dinámica y entre dos objetos que no están relacionados; si el observador posee lo observado, simplemente agregue el observador después de crear o retener lo observado, y retire al observador antes de liberar lo observado.
La adición y eliminación de un objeto como observador generalmente debería ocurrir en la clase del observador, y nunca en el objeto observado.
No soy partidario de esa solución try catch, entonces lo que hago la mayoría del tiempo es crear un método de suscripción y desuscripción para una notificación específica dentro de esa clase. Por ejemplo, estos dos métodos suscriben o anulan la suscripción del objeto a la notificación global del teclado:
@interface ObjectA : NSObject
-(void)subscribeToKeyboardNotifications;
-(void)unsubscribeToKeyboardNotifications;
@end
Dentro de esos métodos, utilizo una propiedad privada que se establece en verdadero o falso, dependiendo del estado de la suscripción, como sigue:
@interface ObjectA()
@property (nonatomic,assign) BOOL subscribedToKeyboardNotification
@end
@implementation
-(void)subscribeToKeyboardNotifications {
if (!self.subscribedToKeyboardNotification) {
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onKeyboardShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onKeyboardHide:) name:UIKeyboardWillHideNotification object:nil];
self.subscribedToKeyboardNotification = YES;
}
}
-(void)unsubscribeToKeyboardNotifications {
if (self.subscribedToKeyboardNotification) {
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillHideNotification object:nil];
self.subscribedToKeyboardNotification = NO;
}
}
@end
[someObject observationInfo]
devuelve nil
si no hay observador.
if ([tableMessage observationInfo] == nil)
{
NSLog(@"add your observer");
}
else
{
NSLog(@"remove your observer");
}