Как вы сообщаете об обновлении только для чтения @property, который зависит от дочерних свойств? - PullRequest
5 голосов
/ 28 февраля 2012

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

@interface MyClass: NSObject {
   Person *_owner;
}
   @property (strong) Person *owner;
   @property (readonly) BOOL hasSomething;
@end

@implementation
   // other code here like -init
   - (void)setOwner:(Person *)newOwner
   {
       [_owner removeObserver:self forKeyPath:@"stuff"];
       _owner = newOwner;
       [_owner addObserver:self forKeyPath:@"stuff" options:0 context:NULL];
   }
   - (Person*)owner
   {
       return _owner;
   }
   - (BOOL)hasSomething
   {
       return owner.stuff > 0;
   }
   - (void)observeValueForKeyPath:(NSString*)kp ofObject:(id)obj change:(NSDictionary*)ch context:(void*)c
   {
       if ([kp isEqualtToString:@"stuff"]) {
           [self willChangeValueForKey:@"hasSomething"];
           [self didChangeValueForKey:@"hasSomething"];
       }
   }
@end

В моем примере все, что связано с hasSomething, не уведомлено должным образом об изменении значения. Чего мне не хватает?

Ответы [ 2 ]

3 голосов
/ 03 марта 2012

Мой обходной путь: Первоначально я работал над этой проблемой, привязываясь прямо к значению, которое я хотел отследить. В приведенном примере это выглядело бы как arrangedObjects.owner.stuff.

Мое решение: Позже я снова посетил код и обнаружил, что то, что я имел, было по существу правильным . Идея заключалась в том, чтобы инкапсулировать внутреннюю работу иерархии объектов (что невозможно, если вы связываете весь путь, как мой обходной путь выше). В этом вопросе я упростил задачу до иерархии с двумя уровнями: MyClass -> Person. Мой код на самом деле включает в себя больше уровней и отношение ко многим. Один из элементов в иерархии неправильно наблюдал за своими дочерними элементами.


Денис предложил мне взглянуть на -automaticallyNotifiesObserversForKey:, и я сделал. Насколько я понимаю, вы хотите, чтобы метод возвращал NO в случае, если вы хотите отправить уведомление вручную в методе установки свойства. В противном случае ваши уведомления конфликтуют с автоматическими.

- (void)setHasSomething:(BOOL)newVal
{
    [self willChangeValueForKey:@"hasSomething"];
    // ...
    [self didChangeValueForKey:@"hasSomething"];
}

Так как нет метода установки для свойства только для чтения, наличие его не решило мою проблему.


Извлеченные уроки: 1) Правильно наблюдайте за своими детьми; 2) Не упрощайте проблему, обращаясь за помощью.

2 голосов
/ 28 февраля 2012

Взгляните сюда https://developer.apple.com/library/ios/DOCUMENTATION/Cocoa/Conceptual/KeyValueObserving/Articles/KVOCompliance.html#//apple_ref/doc/uid/20002178-SW3

Вы должны добавить

+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {

    BOOL automatic = NO;
    if ([theKey isEqualToString:@"hasSomething"]) {
        automatic = NO;
    } else {
        automatic=[super automaticallyNotifiesObserversForKey:theKey];
    }
    return automatic;
}
...