Подтвердить что ты не робот

KVO - Как проверить, является ли объект наблюдателем?

При наблюдении значения объекта с помощью addObserver:forKeyPath:options:context:, в конце концов вы захотите вызвать removeObserver:forKeyPath: на этом объекте, чтобы очистить его позже. Прежде чем это сделать, можно ли проверить, действительно ли объект наблюдает это свойство?

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

4b9b3361

Ответ 1

[...] можно проверить, действительно ли объект наблюдает, что свойство?

Нет. При работе с KVO вы всегда должны иметь в виду следующую модель:

При создании наблюдения вы несете ответственность за удаление этого точного наблюдения. Наблюдение определяется его контекстом, поэтому контекст должен быть уникальным. При получении уведомлений (и, во Льве, при удалении наблюдателя) вы всегда должны проверять контекст, а не путь.

Лучшая практика обработки наблюдаемых объектов заключается в том, чтобы удалить и установить наблюдение в установщике наблюдаемого объекта:

static int fooObservanceContext;

- (void)setFoo:(Foo *)foo
{
    [_foo removeObserver:self forKeyPath:@"bar" context:&fooObservanceContext];

    _foo = foo; // or whatever ownership handling is needed.

    [foo addObserver:self forKeyPath:@"bar" options:0 context:&fooObservanceContext];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (context == &fooObservanceContext) {
        // handle change
    } else {
        // not my observer callback
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

- (void)dealloc
{
    self.foo = nil; // removes observer
}

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

При добавлении наблюдения вы должны сбалансировать это с помощью одного удаления одного и того же наблюдения. Не предполагайте, что вы единственный, кто использует KVO. Классы Framework могут использовать KVO для своих целей, поэтому всегда проверяйте контекст в обратном вызове.

Один последний вопрос, который я хотел бы указать: Наблюдаемое свойство должно соответствовать требованиям KVO. Вы не можете просто наблюдать что-либо.

Ответ 2

Часть протокола NSKeyValueObserving такова:

 - (void *)observationInfo

который должен содержать список наблюдателей.

ИЗМЕНИТЬ  Полезно только для отладки.

Ответ 3

Я недооцениваю этот объективный вопрос. Но так как многие люди используют Swift/target-c вместе, я подумал, что должен подчеркнуть преимущество нового API Swift4 по сравнению со старыми версиями KVO:

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

  • И чтобы удалить себя, вы должны вызывать removeObserver столько раз, сколько вы добавили.
  • Удаление его больше, чем вы добавили, приведет к сбою

Swift4 observe гораздо умнее и swiftier!

  • Если вы делаете это несколько раз, это не волнует. Это не даст несколько обратных вызовов для каждого изменения.
  • И достаточно одного invalidate token.
  • invalidat его перед началом observe или более того, что то, что вы сделали, не приведет к сбою

Чтобы конкретно ответить на ваш вопрос, если вы используете новый Swift4 KVO, вам не нужно об этом заботиться. Просто позвоните и invalidate что все в порядке. Но если вы используете старый API, тогда обратитесь к ответу Николая