如何判断对象是否附加了键值观察器

时间:2009-10-17 15:00:13

标签: objective-c cocoa key key-value-observing

如果你告诉一个目标c对象removeObservers:对于一个密钥路径并且该密钥路径尚未注册,它会破坏sads。喜欢 -

'无法删除关键路径“theKeyPath”的观察者,因为它未注册为观察者。'

有没有办法确定一个对象是否有一个注册的观察者,所以我可以这样做

if (object has observer){
  remove observer
}
else{
  go on my merry way
}

10 个答案:

答案 0 :(得分:310)

尝试捕捉removeObserver调用

@try{
   [someObject removeObserver:someObserver forKeyPath:somePath];
}@catch(id anException){
   //do nothing, obviously it wasn't attached because an exception was thrown
}

答案 1 :(得分:37)

真正的问题是为什么你不知道你是否在观察它。

如果你在观察对象的类中这样做,请停止。无论观察什么,它都希望继续观察它。如果你在不知情的情况下切断了观察者的通知,那么期待事情就会破裂;更具体地说,期望观察者的状态变得陈旧,因为它没有从以前观察到的对象接收更新。

如果您在观察对象的类中执行此操作,只需记住您正在观察的对象(或者,如果您只观察一个对象,是否正在观察它)。这假设观察是动态的,并且在两个不相关的对象之间;如果观察者拥有观察者,只需在创建或保留观察者后添加观察者,并在释放观察者之前移除观察者。

作为观察者添加和删除对象通常应该发生在观察者的类中,而不是在观察对象中。

答案 2 :(得分:25)

FWIW,如果nil没有任何观察员,[someObject observationInfo]似乎是someObject。但是,我不相信这种行为,因为我没有看到它记录在案。另外,我不知道如何阅读observationInfo以获得特定的观察员。

答案 3 :(得分:5)

当您向对象添加观察者时,可以将其添加到NSMutableArray,如下所示:

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

如果您想取消观察对象,可以执行以下操作:

for (id object in _observedObjects) {
    if ([object isKindOfClass:[MyClass class]]) {
        MyClass *myObject = (MyClass *)object;
        [self unobserveMethod:myObject];
    }
}
[_observedObjects removeAllObjects];

请记住,如果您取消观察单个对象,请将其从_observedObjects数组中删除:

- (void)removeObservedObject:(id)object {
    if ([_observedObjects containsObject:object]) {
        [_observedObjects removeObject:object];
    }
}

答案 4 :(得分:4)

执行此操作的唯一方法是在添加观察者时设置标记。

答案 5 :(得分:3)

在我看来 - 这与retainCount机制类似。你无法确定目前是否有观察者。 即使您检查: self.observationInfo - 您也无法确定将来是否有/将不会有观察员。

retainCount 类似。也许 observationInfo 方法不是那么无用,但我只在调试目的中使用它。

因此,您必须像在内存管理中那样执行此操作。如果添加了观察者 - 只需在不需要时将其删除即可。喜欢使用viewWillAppear / viewWillDisappear等方法。 E.g:

-(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:@""];
}

你需要一些特定的检查 - 实现你自己的类来处理一组观察者并用它来进行检查。

答案 6 :(得分:3)

如果没有观察者,

[someObject observationInfo]会返回nil

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

}

答案 7 :(得分:2)

观察者模式的重点是允许观察到的类被“密封” - 不知道或不关心它是否被观察到。您明确试图打破这种模式。

为什么?

你遇到的问题是你假设你没有被观察。这个对象没有开始观察。如果您希望班级控制此过程,则应考虑使用通知中心。这样,您的班级可以完全控制何时可以观察数据。因此,它并不关心谁在观看。

答案 8 :(得分:1)

我不是那种尝试捕获解决方案的粉丝所以 我大部分时间都在做的是,我为该类中的特定通知创建了一个订阅和取消订阅方法。例如,这两个方法将对象描述或取消订阅到全局键盘通知:

@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

在这些方法中,我使用私有属性,根据订阅状态设置为true或false,如下所示:

manage.py celerybeat

答案 9 :(得分:0)

除了亚当的答案,我还建议像这样使用宏

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

用法示例

- (void)dealloc {
    SafeRemoveObserver(someObject, self, somePath);
}
相关问题