|Subject:||Re: Key Value Observation is over reacting|
|Date:||Fri, 14 Dec 2007 14:38:40 +0000|
|User-agent:||GNUMail (Version 1.2.0)|
On 2007-12-14 11:29:41 +0000 Richard Frith-Macdonald <address@hidden> wrote:On 2007-12-14 09:37:32 +0000 "Fred Kiefer" <address@hidden> wrote:-------- Original-Nachricht --------Datum: Fri, 14 Dec 2007 02:11:02 +0100 Von: Markus Hitter <address@hidden> An: Fred Kiefer <address@hidden> CC: GNUstep Developer <address@hidden> Betreff: Re: Key Value Observation is over reactingAm 13.12.2007 um 21:12 schrieb Fred Kiefer:I just see that this special case is not failing there. Should I set breakpoints on methods of the watched instance and check the back trace for on the fly methods?Yes, why not?As for the remaining part, I can't see when the getter method would be used inside KVO at all. Notifications are sent on value changes only, which does the setter. Where does the conflict arise?It is when the KVO code tries to get the value for the key before the change (and also after, but it doesn't get that far). To get the value it uses the valueForKey: method and this fails with an unknown key (OK, the details are a bit more complex, but it boils down to this).Until today, I always thought KVO is based on a mini notification center inside NSObject's -setValue:forKey:. This method would try a few ways to get the variable set, then send a notification to all subscribers on success. No need to patch existing classes.This is only enough for changes done via the setValue:forKey: method, what about normal setter methods, the ones I have this issue with?However, this morning I learned, Apple uses something they call "isa- swizzling":<http://developer.apple.com/documentation/Cocoa/Conceptual/ KeyValueObserving/Concepts/KVOImplementation.html#//apple_ref/doc/uid/ 20002307>This is more or less what GNUstep does as well. It is just the details, which methods will be replaced at which time that make a difference. GNUstep is rather eager at replacing methods. Perhaps we should just replace them when they are actually being watched at least on one object?Perhaps ... thought the current code overriding all setters at once is obviously a bit simpler to code. We should try to mirror apple behavior to minimise the change cof unforseen incompatibilities betwee their and our implementations.In the long run it will probably be best to use a better integration with KVO inside of KVB. There we already know in advance which keys may be watched, perhaps we could do better with that information.I'm fairly convinced now that you are on the right track, but I don't think checking for the existence of a getter method is sufficient. That's because you can get a value using KVC direct from an ivar without using a getter method. So the correct course of action is probably to override the setter if a corresponding getter exists *or* a corresponding ivar exists.I'd still be interesting in a test program to figure out exactly what Apple does though. For instance, when you start observing on an object, do the methods returned by -methodForSelector: for the setters of that object change?I wrote a test program to see when methods were replaced ... MacOS-X only overrides a setter when you ad an observer for the corresponding key, so I think that's what we should do too. I'll look into coding that change now.
I have to leave soon (I'm away for the weeked to go to a christmas party), so I've comitted the work I've done to svn. I don't expect anyone else will be using it so if I've broken KVO that should not cause problems (I did make sure my changes compiled).
Basically the idea was a rewrite so that we only override setters at the point when we first add an observer for the corresponding key. I hope it works, but haven't had any time to test it at all (and I'd also like to clean it up a bit and make sure it raises the same exceptions that apple raises when there are errors).
Anyway, if you can play with it and either fix any problems or email me about them (and I'll try to deal with any issues on monday), I'd be grateful. Otherwise, just use the earlier version from svn. Enjoy.
|[Prev in Thread]||Current Thread||[Next in Thread]|