Как я могу сказать, если объект имеет ключевое значение придает наблюдателя


Если вы скажете объекту objective c removeObservers: для ключевого пути, и этот ключевой путь не был зарегистрирован, он взломает sads. как -

'не удается удалить наблюдателя для ключевого пути "theKeyPath" из-за того, что он не зарегистрирован в качестве наблюдателя.-

есть ли способ определить, имеет ли объект зарегистрированный наблюдатель, поэтому я могу сделать это

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

10 ответов:

положите попробовать поймать вокруг вашего removeObserver вызова

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

реальный вопрос заключается в том, почему вы не знаете, наблюдаете ли вы это или нет.

Если вы делаете это в классе наблюдаемого объекта, остановитесь. Что бы ни наблюдало, оно ожидает, что будет продолжать наблюдать. Если вы отключите уведомления наблюдателя без его ведома, ожидайте, что все сломается; более конкретно, ожидайте, что состояние наблюдателя станет устаревшим, поскольку оно не получает обновлений от ранее наблюдаемого объекта.

Если вы делаете это в наблюдении класс объекта, просто помните, какие объекты вы наблюдаете (или, если вы когда-либо наблюдали только один объект, наблюдаете ли вы его). Это предполагает, что наблюдение является динамическим и между двумя другими несвязанными объектами; если наблюдатель владеет наблюдаемым, просто добавьте наблюдателя после создания или сохранения наблюдаемого и удалите наблюдателя до того, как вы отпустите наблюдаемое.

добавление и удаление объекта в качестве наблюдателя обычно должно происходить в классе наблюдателя, и никогда в наблюдаемом объекте.

FWIW,[someObject observationInfo] кажется nil если someObject нет никаких наблюдателей. Однако я бы не доверял этому поведению, поскольку я не видел его документально. Кроме того, я не знаю, как читать observationInfo чтобы получить конкретных наблюдателей.

когда вы добавляете наблюдателя к объекту, вы можете добавить его в NSMutableArray такой:

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

если вы хотите, чтобы unobserve объекты, которые вы можете сделать что-то вроде:

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

помните, если вы unobserve один объект удалить его из _observedObjects время:

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

единственный способ сделать это-установить флаг при добавлении наблюдателя.

на мой взгляд-это работает аналогично механизму retainCount. Вы не можете быть уверены, что в настоящий момент у вас есть ваш наблюдатель. Даже если вы проверяете: self.observationInfo - вы не можете знать наверняка, что у вас будет / не будет наблюдателей в будущем.

Как retainCount. Может быть, observationInfo метод не совсем такой бесполезный, но я использую его только в целях отладки.

Так что в результате-у вас просто есть чтобы сделать это, как в управлении памятью. Если вы добавили наблюдателя - просто удалите его, когда он вам не нужен. Как использовать viewWillAppear/viewWillDisappear и т. д. методы. Например:

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

и это вам нужны некоторые специфические проверки - реализовать свой собственный класс, который обрабатывает массив наблюдателей и использовать его для проверки.

[someObject observationInfo] return nil если нет наблюдателя.

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

}

весь смысл модели наблюдателя заключается в том, чтобы позволить наблюдаемому классу быть "запечатанным" - не знать или не заботиться о том, наблюдается ли он. Вы явно пытаетесь сломать этот шаблон.

Почему?

проблемы в том, что вы предполагая, что вы наблюдали, когда вы не. Этот объект не начать наблюдения. Если вы хотите, чтобы ваш класс контролировал этот процесс, вам следует рассмотреть возможность использования Центра уведомлений. Таким образом, ваш класс имеет полный контроль над тем, когда данные могут наблюдаться. Следовательно, ему все равно, кто смотрит.

Я не поклонник этой попытки поймать решение так то, что я делаю большую часть времени, заключается в том, что я создаю метод subscribe и unsubscribe для конкретного уведомления внутри этого класса. Например, эти два метода подпишут или отменят подписку объекта на глобальное уведомление клавиатуры:

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

внутри этих методов я использую частное свойство, которое имеет значение true или false в зависимости от состояния подписки, например:

@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

В дополнение к ответу Адама, я хотел бы предложить, чтобы использовать макрос такой

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

пример использования

- (void)dealloc {
    SafeRemoveObserver(someObject, self, somePath);
}