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

если вы сообщите объекту c объекту removeObservers: для ключевого пути и того, что путь ключа не был зарегистрирован, он разбивает сады. как -

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

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

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

Ответ 1

Положите попытку уловить вызов removeObserver

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

Ответ 2

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

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

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

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

Ответ 3

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

Ответ 4

Когда вы добавляете наблюдателя к объекту, вы можете добавить его к 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];
    }
}

Ответ 5

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

Ответ 6

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

Как keepCount. Возможно, метод observInfo не является таким бесполезным, но я использую его только в целях отладки.

Таким образом, вы должны просто сделать это, как в управлении памятью. Если вы добавили наблюдателя, просто удалите его, когда он вам не нужен. Как и при использовании методов 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:@""];
}

И вам нужны определенные проверки - реализуйте свой собственный класс, который обрабатывает массив наблюдателей и использует его для ваших проверок.

Ответ 7

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

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

}

Ответ 8

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

Почему?

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

Ответ 9

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

@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

Ответ 10

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

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

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

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