4
votes

I have a managed object which acts as a playlist, it has a to-many relationship with the playlist items. There can be multiple playlists, but only one "active" playlist. The active playlist is indicated by a boolean attribute on the managed object.

I have the number of items in the active playlist displayed as the badge on a tab bar item. The view controller that the tab bar item represents is listening for a specific notification which is fired when the contents of the active playlist are updated.

I have implemented this in what I feel is a clumsy way and would like to do it better. It does work at the moment but I'm not happy with it.

Currently, each playlist object, on awakeFromFetch, checks to see if it is the active one, and if so registers itself (using key value observing) as an observer for the key path which is the key for the relationship. When it observes a change, it fires the notification, which causes the tab bar item to update itself.

If the playlist loses or gains active status it stops or starts observing itself appropriately, so notifications are only fired from the active playlist.

I would like to drop all of the self-observing KVO code as I am concerned about the various entry and exit points and when to add and remove observers appropriately. It seems too dirty.

I would like to just override didChangeValueForKey:, check and send my notification there if necessary, then call the super implementation. But this is expressly forbidden in the documentation:

didChangeValueForKey:

Invoked to inform the receiver that the value of a given property has changed.

-(void)didChangeValueForKey:(NSString *)key

Parameters

key

The name of the property that changed. Discussion For more details, see Key-Value Observing Programming Guide.

You must not override this method.

So, what can I do?

3

3 Answers

1
votes

I've just read the same documentation, but if you look at the top of the NSManagedObject documentation, it actually says "You are strongly discouraged..."

I guess it all depends on your implementation details. For example, I do the following on a data model that I can modify locally, and sync with a server:

- (void)didChangeValueForKey:(NSString *)key
{
    [super didChangeValueForKey:key];  // MUST CALL THIS!

    if ([key isEqualToString:NSStringFromSelector(@selector(name))] ||
        [key isEqualToString:NSStringFromSelector(@selector(text))] ||
        [key isEqualToString:NSStringFromSelector(@selector(filename))]
        )
    {
        self.lastModified = [NSDate date];
    }
}

I'm not sure why this would be considered bad. It's just saying "Do what you normally do. In addition, I'd like to set another property that depends on that change."

0
votes

What you want is Key Value Observing. You should be able to register for that specific key, and get notified when it changes. Check this out too: Using KVO to observe changes to a property on an object inside a collection in Objective-C

0
votes

I have solved this by making a separate object (a singleton I am using to manage my core data stack) the observer instead. All of the self-observing complexity has now gone and I do not need to worry about adding or removing observers on awakeFromFetch and so on.