Question

I've done some simple KVO setups. Now I have a bit more complex one. I have a singleton object that is settable. That is reachable with code like

[Site singleton].value

I can (and have) watch that singleton for changes in it's value property. But I would also like to watch a property of the current value (IF it's not nil). It has a valves property that I would like to notice changes in.

Without knowing any better, I guess I can do something like

  1. Observe the value property like I'm used to
  2. When that changes, register a watch on the current value's valves property as well IF it is non nil
  3. Also, somehow, not sure how to do this, unregister any valves watching it was doing on the previous value.

This seems... burdensome.

I see that you can do more complex keyPaths but I've not found documentation that explains how to use them. Are they something that could make this problem easier? If not, is this a pattern that others have found a good solution for?

Était-ce utile?

La solution

I can provide a better answer if I know a little more about the code involved, but this should be easy. I will assume that the observer is a view controller, but this is the most straightforward way of setting this up.

- (void)viewWillAppear:(BOOL)animated
{
    // …
    [[Site singleton] addObserver:self forKeyPath:@"value" options:0 context:NULL];
    [[Site singleton] addObserver:self forKeyPath:@"value.valves" options:0 context:NULL];
}

- (void)viewWillDisappear:(BOOL)animated
{
    // …
    [[Site singleton] removeObserver:self forKeyPath:@"value"];
    [[Site singleton] removeObserver:self forKeyPath:@"value.valves"];
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    if ([keyPath isEqualToString:@"value"]) {
        // …
    } else if ([keyPath isEqualToString:@"value.valves"]) {
        // …
    }
}

See Key-Value Coding Fundamentals.

Words of advice for KVO

  1. Observe something that you know the full lifecycle of. A singleton is a good choice as long as it truly lives the whole life of the application. Generally, I stick to objects observing themselves.

  2. Add an observer right when you need to do observing, remove an observer as soon as you no longer need observing. Always adding an observer in -init* and removing it in -dealloc is asking for trouble.

Autres conseils

Yes, you can observe the keyPath @“value.valves” on self.singleton in:

- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;

You’ll be notified whenever value changes OR valves changes on it.

NOTE, however, that if value ever changes without correctly posting a willChange.../didChange..., you’ll get a run-time error. Mostly ‘value’s notifications will be posted for you by setter machinery, but if you have a weak reference to it, it can delete itself without posting, which is super-annoying and a really stupid thing the clang team did.

Also note that if valves is a mutableArray you’re playing with fire, because it’ll mutate without you being notified.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top