¿Cómo puedo saber si un objeto tiene un observador de valor clave adjunto


Si le dice a un objeto objective c que elimine Observervers: para una ruta de acceso de clave y esa ruta de acceso de clave no se ha registrado, agrieta el sads. como -

'No puede eliminar a un observador de la ruta de clave "theKeyPath" porque no está registrado como observador.'

¿Hay una manera de determinar si un objeto tiene un observador registrado, por lo que puedo hacer esto

if (object has observer){
  remove observer
}
else{
  go on my merry way
}
Author: Shoban, 2009-10-17

10 answers

Poner un intento de captura alrededor de su llamada removeObserver

@try{
   [someObject removeObserver:someObserver forKeyPath:somePath];
}@catch(id anException){
   //do nothing, obviously it wasn't attached because an exception was thrown
}
 302
Author: Adam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-16 11:14:48

La verdadera pregunta es por qué no sabes si lo estás observando o no.

Si está haciendo esto en la clase del objeto que se está observando, deténgase. Lo que sea que esté observando espera seguir observándolo. Si corta las notificaciones del observador sin su conocimiento, espere que las cosas se rompan; más específicamente, espere que el estado del observador se vuelva obsoleto, ya que no recibe actualizaciones del objeto observado anteriormente.

Si está haciendo esto en la clase del objeto de observación, simplemente recuerde qué objetos está observando (o, si solo observa un objeto, si lo está observando). Esto es asumiendo que la observación es dinámica y entre dos objetos no relacionados; si el observador posee el observado, simplemente agregue el observador después de crear o retener el observado, y elimine el observador antes de liberar el observado.

La adición y eliminación de un objeto como observador debería ocurrir normalmente en la clase del observador, y nunca en la clase observada objeto.

 36
Author: Peter Hosey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-17 16:28:54

FWIW, [someObject observationInfo] parece ser nil si someObject no tiene ningún observador. No confiaría en este comportamiento, sin embargo, ya que no lo he visto documentado. Además, no se como leer observationInfo para conseguir observadores específicos.

 22
Author: ma11hew28,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-02 14:17:48

Cuando añades un observador a un objeto podrías añadirlo a un NSMutableArray así:

- (void)addObservedObject:(id)object {
    if (![_observedObjects containsObject:object]) {
        [_observedObjects addObject:object];
    }
}

Si quieres no observar los objetos puedes 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];
    }
}
 5
Author: Oritm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-04 14:56:34

La única manera de hacer esto es establecer una bandera cuando se agrega un observador.

 3
Author: Leibowitzn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-17 17:12:58

En mi opinión, esto funciona de manera similar al mecanismo de retainCount. No puedes estar seguro de que en este momento tengas a tu observador. Incluso si se comprueba: auto.observationInfo - usted no puede saber con seguridad que usted tendrá/no tendrá observadores en el futuro.

Como retainCount. Tal vez el método observationInfo no es exactamente ese tipo de inútil, pero solo lo uso con fines de depuración.

Así que, como resultado, solo tienes que hacerlo como en la memoria gestión. Si agregaste un observador, simplemente elimínalo cuando no lo necesites. Como usar viewWillAppear / viewWillDisappear etc. método. Por ejemplo:

-(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 maneje una matriz de observadores y utilícela para sus comprobaciones.

 3
Author: quarezz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-03 11:34:13

[someObject observationInfo] devuelve nil si no hay ningún observador.

if ([tableMessage observationInfo] == nil)
{
   NSLog(@"add your observer");
}
else
{
  NSLog(@"remove your observer");

}
 3
Author: Anupama,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-11 00:05:56

El objetivo del patrón del observador es permitir que una clase observada sea "sellada" to para no saber o preocuparse si está siendo observada. Usted está explícitamente tratando de romper este patrón.

¿Por qué?

El problema que tienes es que asumes que estás siendo observado cuando no lo eres. Este objeto no inició la observación. Si quieres que tu clase tenga el control de este proceso, entonces deberías considerar usar el centro de notificaciones. De esa manera su clase tiene lleno control de cuándo se pueden observar los datos. Por lo tanto, no le importa quién está mirando.

 2
Author: adonoho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-11 00:06:17

No soy fan de esa solución try catch, así que lo que hago la mayoría de las veces es crear un método de suscripción y cancelación de suscripción para una notificación específica dentro de esa clase. Por ejemplo, estos dos métodos suscriben o cancelan la suscripción del objeto a la notificación global de teclado:

@interface ObjectA : NSObject
-(void)subscribeToKeyboardNotifications;
-(void)unsubscribeToKeyboardNotifications;
@end

Dentro de esos métodos utilizo una propiedad privada que se establece en true o false dependiendo del estado de suscripción de la siguiente manera:

@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
 1
Author: Sebastian Boldt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-22 07:11:17

Además de la respuesta de Adán me gustaría sugerir el uso de macro como este

#define SafeRemoveObserver(sender, observer, keyPath) \
@try{\
   [sender removeObserver:observer forKeyPath:keyPath];\
}@catch(id anException){\
}

Ejemplo de uso

- (void)dealloc {
    SafeRemoveObserver(someObject, self, somePath);
}
 0
Author: wattson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-24 02:07:36