Re: Crash on NSKVOPendingNotificationRelease (KVO, bindings issue?)

2010-04-21 Thread Quincey Morris
On Apr 21, 2010, at 17:47, Glen Low wrote:

> I'm using KVO as a generalized recalculation engine, somewhat akin to how a 
> spreadsheet recalcuates values based on what's changed. It's mostly 
> successful once you eliminate cycles, but there is a persistent problem.

The likely answer (see below for the reasons) is that this is probably not a 
good approach. Your application needs a specific behavior of change 
propagation, cycle elimination -- as well as other possible constraints -- that 
KVO has no API contract to provide. I'd recommend you spend the effort on 
designing your own object graph and related behavior.

> On each relevant object, I have a 
> observeValueForKeyPath:ofObject:change:context: method which then triggers 
> willChangeValueForKey:  / didChangeValueForKey: for dependent properties. 
> I've noticed that when observeValueForKeyPath:ofObject:change:context gets 
> called more than once in a row for an object, one of the other observed 
> objects dies in didChangeValueForKey: -- here's the stack trace

I *believe* that KVO contains at least one (major? inherent?) bug that causes 
crashes like this with certain patterns of observations. Whenever I run into 
such crashes, I've never been able to work out whether it is in fact a bug, or 
if I did something wrong, nor to recreate the crash in a more controlled 
context that could be used as the basis of a bug report.

So you might have run into a bug. Or you might have set up an observation 
pattern that KVO doesn't really support (either at the level of observers or 
the level of notifications).

KVO has two important defects from the developer's point of view: it's a black 
box system, so trying to understand what it's doing at any given moment is pure 
guesswork; and it's an implementation-defined system, so that beyond its 
general responsibilities, what is does is what it's "supposed to" do, and 
there's no independent standard of whether it's right or wrong.

Plus, KVO probably doesn't scale well as the number of observations increases. 
If your object graph is going to get large, performance may well become a 
consideration.

For all those reasons, I wouldn't suggest using it for an application like 
this, where *propagation* of the notifications across multiple objects is the 
key functional issue.

FWIW.

> Side question: I can of course use keyPathsForValuesAffectingValueForKey: and 
> friends to declare the dependencies instead of using a procedure to react to 
> them, but I need to execute code as well e.g. update the observed value. For 
> example, say A = B/C. When either B or C changes, you want A to change too. I 
> can use keyPathsForValuesAffectingA to declare it depends on B or C, but I 
> need to update the cached A value whenever B or C changes -- how would I do 
> that without using observeValueForKeyPath:ofObject:change:context:?

If you really need to "cache" the A value, then you have to use 
observeValueForKeyPath:ofObject:change:context:. Using 
keyPathsForValuesAffectingA only makes sense if you're going to produce the A 
value on demand.

Incidentally, this example points another defect of using KVO for your 
application. You want A to change when B or C changes, and it will -- 
literally, meaning twice. Once for the B change, and once for the C change. 
That means that A may temporarily have an invalid value, and that might itself 
be propagated via notifications before its final value is calculated. KVO 
guarantees no order for the notifications, and although in a few cases it might 
optimize some repeated notifications away you don't have a lot of control over 
the quantity of notifications that get sent.


___

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 arch...@mail-archive.com


Crash on NSKVOPendingNotificationRelease (KVO, bindings issue?)

2010-04-21 Thread Glen Low
I'm using KVO as a generalized recalculation engine, somewhat akin to how a 
spreadsheet recalcuates values based on what's changed. It's mostly successful 
once you eliminate cycles, but there is a persistent problem.

On each relevant object, I have a 
observeValueForKeyPath:ofObject:change:context: method which then triggers 
willChangeValueForKey:  / didChangeValueForKey: for dependent properties. I've 
noticed that when observeValueForKeyPath:ofObject:change:context gets called 
more than once in a row for an object, one of the other observed objects dies 
in didChangeValueForKey: -- here's the stack trace

Program received signal:  “EXC_BAD_ACCESS”.

#0  0x7fff84d31ae1 in NSKVOPendingNotificationRelease
#1  0x7fff88aa0bd3 in __CFArrayReleaseValues
#2  0x7fff88a815f8 in _CFArrayReplaceValues
#3  0x7fff84d31e35 in NSKeyValuePopPendingNotificationPerThread
#4  0x7fff84d31dca in NSKeyValueDidChange
#5  0x7fff84d1574f in -[NSObject(NSKeyValueObserverNotification) 
didChangeValueForKey:]
#6  0x1000181c8 in -[CMEdge didChangeValueOnceForKey:] at CMEdge.m:133
#7  0x100019f51 in -[CMNode 
observeValueForKeyPath:ofObject:change:context:] at CMNode.m:222

The only workaround is to perform the didChangeValueForKey: in the next event 
cycle i.e. by using performSelectorOnMainThread:withObject:waitUntilDone:

Not really ideal especially since I'm worried I'm just covering up the root of 
the problem, whatever it is.

Any ideas on the cause?

Side question: I can of course use keyPathsForValuesAffectingValueForKey: and 
friends to declare the dependencies instead of using a procedure to react to 
them, but I need to execute code as well e.g. update the observed value. For 
example, say A = B/C. When either B or C changes, you want A to change too. I 
can use keyPathsForValuesAffectingA to declare it depends on B or C, but I need 
to update the cached A value whenever B or C changes -- how would I do that 
without using observeValueForKeyPath:ofObject:change:context:?

Cheers
Glen Low
Pixelglow Software___

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 arch...@mail-archive.com