FROM : George Orthwein
DATE : Thu Jul 20 21:25:20 2006
On Jul 18, 2006, at 8:44 PM, Matt Neuburg wrote:
> Interestingly, though (or perhaps not, for those who already
> realized this),
> if what you are planning to do when you get notified thru
> observeValue... is
> set a corresponding ivar, it might be much simpler to avoid the entire
> problem and use bind:... instead of addObserver:... at the outset.
Thanks for this idea, though I actually arrived at my current
observeValueForKeyPath: implementation because I had initially using
bindings! :)
http://www.cocoabuilder.com/archive/message/cocoa/2006/4/17/161225
I already had all the setters there that were called with
bind:toObject:withKeyPath:options: so when I switched to KVO, it
naturally led into trying to call them from my
observeValueForKeyPath: method.
One nice thing is that I can switch back and forth easily just by
swapping out:
[sender bind:@"attributeName" toObject:docPrefsController
withKeyPath:@"selection.attributeName" options:nil];
for
[docPrefsController addObserver:sender
forKeyPath:@"selection.attributeName" options:nil context:NULL];
As you point out, one passes through observeValueForKeyPath: and one
calls the accessors directly.
The main reason I switched away from using bind: was that I found my
setters getting called something like a dozen times when the binding
was first initiated with bind:toObject:withKeyPath:options:. Perhaps
there's a way to coalesce those initial updates. I found it was
bogging down the initial display of the view since it triggered a
dozen or so redraws.
(Ok, I just double checked this and I'm only seeing a single initial
call now when I use bind:! Not sure what I was seeing before because
in my notes I even mention some accessors getting called 24 times! I
probably setup something wrong at some point, though I thought I had
also seen this mentioned in the archives somewhere. More
investigation is in order....)
One thing that tripped me up when I switched to KVO is that
addObserver:forKeyPath:options:context: does NOT send the current
value on initial registration. This means that to sync the view
initially I have to enumerate through the relevant attributes and
call setValue:forKey: manually.
http://www.cocoabuilder.com/archive/message/cocoa/2006/5/20/163920
> The point there was that if I say bind:..., I get a "one-way"
> binding, which
> in effect means that I start observing the thing I'm bound to. In that
> thread I was concentrating on the downside, which is that the thing
> I'm
> bound to does not automatically also start observing me; but now
> let's talk
> about the upside. The upside is that my ivar gets set automatically
> when the
> other object's observed attribute changes - without ever passing
> through
> observeValue...!
>
> So, if what you were going to do was call setValue:forKey: on your
> own ivar,
> you could skip the whole addObserver: thing and just use bind:,
> because
> that's exactly what then *will* happen; setValue:forKey: will be
> called on
> your ivar.
True. I guess if you want to avoid the KVO "bottleneck" you can just
use "one way" bindings instead!
> Moreover, in the case of something like an NSController's
> "content", this
> approach works, when ordinary observing with addObserver: does not.
> As has
> been pointed out several times recently, the change dictionary
> passed to
> observeValue... is empty. But if you start with bind:, it works
> great; the
> new value just gets handed to you directly.
Is this right?. If you bind to "arrangedObjects" the entire array is
sent each time it is modified. I tried binding to "content" and
wasn't getting any updates on modifications so maybe my test was
wrong anyhow. But it doesn't look like you can get just the change/
removed values using bind.
> Of course this is officially a misuse of bindings,
I don't think implementing "one way" or "read only" bindings is a
misuse, though it almost seems that way since there aren't any
examples or mentions of it in the docs that I remember seeing. I
think I'll file a doc request.
It does seem to be a sly way of avoiding the observeValueForKeyPath
bottleneck though.
I think I better add a disclaimer since many details of this whole
thing are still fuzzy in my head: Anything stated above may be
completely wrong. There, I feel better. ;)
George
DATE : Thu Jul 20 21:25:20 2006
On Jul 18, 2006, at 8:44 PM, Matt Neuburg wrote:
> Interestingly, though (or perhaps not, for those who already
> realized this),
> if what you are planning to do when you get notified thru
> observeValue... is
> set a corresponding ivar, it might be much simpler to avoid the entire
> problem and use bind:... instead of addObserver:... at the outset.
Thanks for this idea, though I actually arrived at my current
observeValueForKeyPath: implementation because I had initially using
bindings! :)
http://www.cocoabuilder.com/archive/message/cocoa/2006/4/17/161225
I already had all the setters there that were called with
bind:toObject:withKeyPath:options: so when I switched to KVO, it
naturally led into trying to call them from my
observeValueForKeyPath: method.
One nice thing is that I can switch back and forth easily just by
swapping out:
[sender bind:@"attributeName" toObject:docPrefsController
withKeyPath:@"selection.attributeName" options:nil];
for
[docPrefsController addObserver:sender
forKeyPath:@"selection.attributeName" options:nil context:NULL];
As you point out, one passes through observeValueForKeyPath: and one
calls the accessors directly.
The main reason I switched away from using bind: was that I found my
setters getting called something like a dozen times when the binding
was first initiated with bind:toObject:withKeyPath:options:. Perhaps
there's a way to coalesce those initial updates. I found it was
bogging down the initial display of the view since it triggered a
dozen or so redraws.
(Ok, I just double checked this and I'm only seeing a single initial
call now when I use bind:! Not sure what I was seeing before because
in my notes I even mention some accessors getting called 24 times! I
probably setup something wrong at some point, though I thought I had
also seen this mentioned in the archives somewhere. More
investigation is in order....)
One thing that tripped me up when I switched to KVO is that
addObserver:forKeyPath:options:context: does NOT send the current
value on initial registration. This means that to sync the view
initially I have to enumerate through the relevant attributes and
call setValue:forKey: manually.
http://www.cocoabuilder.com/archive/message/cocoa/2006/5/20/163920
> The point there was that if I say bind:..., I get a "one-way"
> binding, which
> in effect means that I start observing the thing I'm bound to. In that
> thread I was concentrating on the downside, which is that the thing
> I'm
> bound to does not automatically also start observing me; but now
> let's talk
> about the upside. The upside is that my ivar gets set automatically
> when the
> other object's observed attribute changes - without ever passing
> through
> observeValue...!
>
> So, if what you were going to do was call setValue:forKey: on your
> own ivar,
> you could skip the whole addObserver: thing and just use bind:,
> because
> that's exactly what then *will* happen; setValue:forKey: will be
> called on
> your ivar.
True. I guess if you want to avoid the KVO "bottleneck" you can just
use "one way" bindings instead!
> Moreover, in the case of something like an NSController's
> "content", this
> approach works, when ordinary observing with addObserver: does not.
> As has
> been pointed out several times recently, the change dictionary
> passed to
> observeValue... is empty. But if you start with bind:, it works
> great; the
> new value just gets handed to you directly.
Is this right?. If you bind to "arrangedObjects" the entire array is
sent each time it is modified. I tried binding to "content" and
wasn't getting any updates on modifications so maybe my test was
wrong anyhow. But it doesn't look like you can get just the change/
removed values using bind.
> Of course this is officially a misuse of bindings,
I don't think implementing "one way" or "read only" bindings is a
misuse, though it almost seems that way since there aren't any
examples or mentions of it in the docs that I remember seeing. I
think I'll file a doc request.
It does seem to be a sly way of avoiding the observeValueForKeyPath
bottleneck though.
I think I better add a disclaimer since many details of this whole
thing are still fuzzy in my head: Anything stated above may be
completely wrong. There, I feel better. ;)
George






Cocoa mail archive

