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

Reply via email to