17
votes

I'm using KVC/KVO to create a custom bindings implementation for a University project (it needs to be custom as I want to do things beyond what bindings can do, including running on iOS).

I have a 'bindings controller' that registers for KVO notifications on a number of keys on an object (using addObserver:forKeyPath:options:context:) and I do receive notifications. However I am receiving two notifications for each change. I have an idea for a workaround, but I would rather work out why this is happening and correct it!

Does anyone have any ideas why this might be happening? I'm certain I have only registered each notification a single time, and deregistering a single time causes both of the notifications to stop.

Thanks.

Edit:

I have a request for some code, so I'll put some in. It's a bit rough at the moment, it's essentially still a proof of concept, so bear with me.

This is one of the properties I am observing (I know it's a bit strange, but this class essentially exposes certain properties of an NSManagedObject as properties of itself):

- (void)setName:(NSString *)name
{
    [self willChangeValueForKey:@"name"];
    [contact setFirstName:name];
    [self didChangeValueForKey:@"name"];
}

This is the code I use to observe that property (confirmed to only run once, and only in a single place):

[viewModel addObserver:self
            forKeyPath:@"name"
               options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial)
               context:viewController];

Any calls after that which change that property, e.g.:

viewModel.name = @"Joe";
[viewModel setName: @"Joe"];
[viewModel setValue: @"Joe" forKey: @"name"];

will cause the method:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context

to be called twice, with the same arguments each time.

2

2 Answers

22
votes

You're doing this:

- (void)setName:(NSString *)name
{
    [self willChangeValueForKey:@"name"];
    [contact setFirstName:name];
    [self didChangeValueForKey:@"name"];
}

But (by the sounds of it) from a non-NSManagedObject subclass. This means that Cocoa will be attempting to send KVO notifications automatically for you. You're supplementing that by sending your own too. Solutions:

  • Override +automaticallyNotifiesObserversForKey: to return NO
  • Change your method to:

    - (void)setName:(NSString *)name { [contact setFirstName:name]; }

1
votes

Perhaps put an NSLog in your addObserver call, to see if you're adding two observers.