Summary:

    KVO compliance discussion
    Detailed problem description
    Request (to Jens) for clarification
    What I've tried
    A failed workaround
    A crappy, unsound workaround


Hi Jens, Jack and List Participants,

Thanks, Jens, for your reply.

On 4/5/08, Jens Alfke wrote:

Cannot remove an observer <NSTableBinder 0x158a70> for the key path "name" from <Alternative 0x15abd0> because it is not registered as an observer.

"It" refers to the observer. -removeObserver:forKeyPath: raises this
exception if told to remove an object that isn't currently registered
as an observer. So what's happening is that a table view is trying to
unregister as an observer from one of your objects that it
unfortunately didn't previouly register as an observer for.

The usual cause of this is that you have a property that isn't KVO-compliant.

All my properties have a setters and getters and have the appropriate calls to

    will|did Access|Change ValueForKey

before/after any change.  Is there more that I need to do?

For what its worth, let me explain exactly what is causing the problem.

Firstly, the 'Contribution' Entity is more-or-less a many to many join table (but with a 'degree' attribute) between 'Alternatives' and 'Values'.

I have a simple but unusual arrangement of what is displayed in the 'degree' column of my 'Alternatives' tableView. Depending on the selection in a 'Values' tableView, I show the 'degree' attribute of a certain set of 'Contribution' objects (basically, the related 'Contributions' of the selected 'Value' -- there will be one for each 'Alternative'). i.e. Every time the user changes the 'Values' table selection, the degree column of the Alternatives' tableView changes to show the 'degree' attributes of a new set of 'Contributions'. That change causes the "cannot remove an observer" exceptions.

Simple idea, hard to explain. It could more easily have been a very wide tableView with a column for each 'Contribution', the column label being the name of the relevant 'Value'. The current technique avoids at least three undesirable aspects:

    variable number of table columns,
    truncated column labels,
    horizontal scrolling.

Those undesirables will be even more so when the app is also a web app.

Something accesses your 'foo' property and registers as an observer of
that property, and also as an observer of the object that's the
property's current value;

Jens, can you please elaborate on that distinction? I was not aware that something could be an observer of an object.

you change the value of 'foo' without letting anyone know; the
observer then later decides to stop observing, gets your 'foo'
property, and removes itself as an observer of that object. But it's
no longer the same object that it registered as an observer for...

OK. I made a guess that the culprit was ether the 'Alternative' tableView or the 'Alternative' ArrayController. So, in my WindowController's awakeFromNib, I tried adding them as observers for the 'degree' property (the one the exception complains about) for all 'Contribution' objects, like so:

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity: [NSEntityDescription entityForName: @"Contribution" inManagedObjectContext: [self managedObjectContext]]];

NSArray *contributions = [[self managedObjectContext] executeFetchRequest: fetchRequest error: &error];
    [fetchRequest release];

    for (Contribution *aContribution in contributions)
    {
        [aContribution  addObserver: alternativeTableView
                         forKeyPath: @"degree"
options: (NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
                            context: NULL];
        [aContribution  addObserver: alternatives
                         forKeyPath: @"degree"
options: (NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
                            context: NULL];
    }

It didn't help. Either the addObserver is insufficient or I still don't know what the "it" is in the error message. (Or, I've created over-observance as mentioned by Jack.)

In desperation, I added try-catch around each step of the code that throws exceptions and discovered that these two lines throw :

[selectedAlternative setContributionForSelectedDecisionValue: nil]; // KVO dummy setter
    [alternativeArrayController     rearrangeObjects];

but this line doesn't throw

    [alternativeTableView   reloadData];

In the short-term, I've caught the two exceptions -- that has allowed the application to more-or-less work. But it doesn't bode well for the future. For one thing, any subsequent [alternativeArrayController rearrangeObjects] will fail.

I know of at least two other people struggling with this problem and have seen others encounter it in the past. It would be great to have an answer here in the list archives.

Thanks,

Steve

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [EMAIL PROTECTED]

Reply via email to