Jef
Jef

Reputation: 2134

KVO: Cannot remove an observer

In my interface I have an NSTextField who's value is bound to an NSArrayController's selection.selectedType.title. All of the NSArrayController's objects are custom objects each with two methods:

- (MYType *)selectedType;
- (void)setSelectedType: (MYType *)type;

The don't have an iVar selectedType. However, they do have an iVar holding all MYType objects. The code boils down to this:

- (MYType *)selectedType
{
   if (someIndex == 0)
        return [types objectAtIndex: 0];
    else
        return [self typeWithIndex: someIndex];
}

- (void)setSelectedType: (MYType *)type
{
     someIndex = [type index];  
}

MYType objects got a NSString *title iVar with a corresponding @property and synthesize.

Whenever I call setSelectedType:, the changes are immediately visible in the NSTextField and everything seems to work but I get a log message saying:

Cannot remove an observer NSArrayController 0x141160 for the key path "selectedType.title" from MYType 0x1a4830, most likely because the value for the key "selectedType" has changed without an appropriate KVO notification being sent. Check the KVO-compliance of the MYType class.

I tried encapsulating the setSelectedType: method with willChangeValueForKey: and didChangeValueForKey: and then I still got a log message but a different one:

Cannot remove an observer NSKeyValueObservance 0x1c7570 for the key path "title" from MYType 0x1a4be0 because it is not registered as an observer.

Upvotes: 4

Views: 3384

Answers (2)

Mark Bridges
Mark Bridges

Reputation: 8448

I ran into this same error but for a different reason. Probably worth mentioning it in case anyone else winds up here.

I'm writing an app in Swift and I'd forgotten to prefix the var with dynamic

Upvotes: 1

Rob Napier
Rob Napier

Reputation: 299265

First, use accessors. Don't access your ivars directly. You're bypassing the KVO for someIndex because you modify the ivar directly. Don't touch ivars directly unless you have to.

You also need to let KVO know that selectedType depends on someIndex (and/or someStuff; it's not clear from your distilled code).

+ (NSSet *)keyPathsForValuesAffectingSelectedType
{
  return [NSSet setWithObjects:@"someIndex", nil];
}

This tells the KVO system that whenever someIndex changes, it causes an implicit change in selectedType. See Registering Dependent Keys.

Upvotes: 5

Related Questions