你如何表示对依赖于子属性的只读@property的更新?

5 cocoa objective-c key-value-observing

这是一个简单的例子,对于这个问题应该足够了.

@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
Run Code Online (Sandbox Code Playgroud)

在我的例子中,任何绑定的东西hasSomething都没有被正确地通知值的变化.我错过了什么?

小智 3

我的解决方法: 我最初通过直接绑定到我想要跟踪的值来解决这个问题。在给出的示例中,它看起来像arrangedObjects.owner.stuff

我的解决方案: 后来我重新审视了代码,发现我所得到的基本上是正确的。这个想法是封装对象层次结构的内部工作(如果您像上面的解决方法一样绑定整个路径,则无法实现)。在问题中,我将问题简化为具有两个级别的层次结构:MyClass -> Person。我的代码实际上涉及更多的层次和一对多的关系。层次结构中的元素之一是没有正确观察其子元素。


丹尼斯建议我看一下,-automaticallyNotifiesObserversForKey:我就看了。NO根据我的理解,如果您想在属性的 setter 方法中手动发送通知,您可能希望该方法返回。否则,您的通知会与自动通知发生冲突。

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

由于只读属性没有 setter 方法,因此它并不能解决我的问题。


经验教训: 1)正确观察孩子;2)寻求帮助时不要过度简化你的问题。