views:

195

answers:

3

I'd like to monitor an NSCountedSet to see if its contents changes. Setting up KVO seems to compile but it's not being triggered. First question: can you observe a set? If so then is there something wrong with this message?

    [subViewA addObserver:subViewB forKeyPath:@"countedSet" options:0 context:NULL];

I'm really just trying to monitor the count of (number of objects in) the set if that helps.

Edit - here's the observer (subViewB):

- (void)observeValueForKeyPath:(NSString *)keyPath 
          ofObject:(id)object 
         change:(NSDictionary *)change 
           context:(void *)context {
    if ([keyPath isEqual:@"countedSet"]) {
     NSLog(@"Set has changed");
    }
}

Edit2 - moved the addObserver message from the subView to the viewController. So I'm trying to get one subView to observe a NSCountedSet in another of the viewController's subViews. key path is "relative to the receiver" - which I assume to be subViewA.

+3  A: 

There are definitely KVO manual change methods for unordered to-many relationships.

Don't you want to be setting your options to non-zero? For instance, NSKeyValueObservingOptionNew

Also Mike Ash's KVO Helper is pretty excellent.

From the NSSet docs on addObserver:

NSSet objects are not observable, so this method raises an exception when invoked on an NSSet object. Instead of observing a set, observe the unordered to-many relationship for which the set is the collection of related objects.

nall
I suppose but I'm still not getting my observer to fire...
Meltemi
I don't even know what that last bit you added "... Instead of observing a set, observe the unordered to-many relationship for which the set is the collection of related objects" means?!? So sets cannot be observed?
Meltemi
But I'm not trying to observe the "NSSet Objects". I just want to observe the set itself...or more specifically the "count" of the set. If the number of objects it contains grows or shrinks I want my observer to be notified...if possible.
Meltemi
Take a look at mutableSetForValue: Automatic notification is also supported for the collection proxy objects returned by mutableArrayValueForKey: and mutableSetValueForKey: . This works for to-many relationships that support the indexed accessor methods insertObject:in<Key>AtIndex:, replaceObjectIn<Key>AtIndex:, and removeObjectFrom<Key>AtIndex:. http://bit.ly/r0A20
nall
The indexed accessors only apply to arrays. There are, however, accessor patterns for sets as well (`add<Key>Object:`, etc.).
Peter Hosey
A: 

Some things to check:

  1. Is myController non-nil? If it's nil, the addObserver:::: message simply falls on the floor silently.
  2. Is your method getting called at all? Perhaps it's being called, but not with the key path you expect. (I wouldn't expect this, either, but it's worth checking.)
Peter Hosey
I verified myController is non-nil. Even moved some things around but to no avail... and NO, the observeValueForKeyPath method is NOT getting called at all. so wiring must be screwy.
Meltemi
+3  A: 

Talking directly to the set object does not issue KVO change notifications. You need to make changes to the property's set value in a KVC-compliant way. There are two ways:

  1. Send the property owner a mutableSetValueForKey: message. This will give you a fake set object that wraps the property and posts KVO notifications around each change you make to it.
  2. Implement the set accessor methods for the property, and use them everywhere. The implementation of each method talks directly to the underlying set object; all code that isn't in one of these methods should go through them. So, for example, to add an object, you should not use [myCountedSet addObject:foo] (except in addCountedSetObject:); you should use [self addCountedSetObject:foo] instead.

I recommend #2. It may sound like more work, but it's not much, and it makes for really good code.

More details in the Model Object Implementation Guide and in the Core Data Programming Guide (even though this is not specific to Core Data).

Peter Hosey
Note that this is also true for arrays. If you mutate a mutable array out from under KVO, it won't send notifications.
Chuck