objective-ckey-value-observingnsmutableset

Key-Value Observing an NSMutableSet


In a plain class I have a NSMutableSet property. Whenever objects are added to or removed from the set, I want to perform some custom code. I know I could write a few addObjectToSet:-like methods to the class, but I was wondering if there's a more elegant solution with direct KVO on the set.

As it turns out, NSSet will raise an exception when you try to add an observer to it. Not surprisingly, for there's probably no named keyPath to observe. The documentation is pretty clear about the exception, but I don't understand the suggested workaround:

Instead of observing a set, observe the unordered to-many relationship for which the set is the collection of related objects.

Could someone reiterate what this means? And what a workaround would then look like?


Solution

  • That's a pretty dense way of saying "don't add an observer to the set itself, add an observer to the class that contains the set":

    [myObjWithASetAsIvar addObserver:self
                          forKeyPath:@"nameOfIvarHoldingTheSet"
                             options:NSKeyValueObservingOptionNew
                             context:nil];
    

    The one tricky bit is that you need to wrap all your accesses to the set in order for the proper notifications to be sent. In the class containing the set:

    [self willChangeValueForKey:@"nameOfIvarHoldingTheSet"];
    // Do something with the set
    [self didChangeValueForKey:@"nameOfIvarHoldingTheSet"];
    

    There are also two notification methods specifically for sets: willChangeValueForKey:withSetMutation:usingObjects: and didChangeValueForKey:withSetMutation:usingObjects:; you may find that they work better for you than the generic "value change" methods.

    All that said, I believe that the solution you mentioned in your first paragraph, and outlined by Peter Hosey in the question Girish linked to, is probably the best way to go.