Re: NSArrayController Frustration
Re: NSArrayController Frustration
- Subject: Re: NSArrayController Frustration
- From: Steve Weller <email@hidden>
- Date: Sun, 25 Nov 2007 21:30:46 -0800
On Nov 25, 2007, at 8:50 PM, Chris Hanson wrote:
On Nov 24, 2007, at 5:58 PM, David Carlisle wrote:
I am expecting that when I do [docArray addObject:x] that the
array controller will observe the change and do a reloadData on
the NSTableView. That isn't happening.
Your expectation is incorrect. What your NSArrayController is
bound to is not the docArray *object* but the docArray *property*
(or key) of your NSWindowController subclass.
There are a few different ways you can resolve this. You've
proposed one yourself -- to do all manipulations via the
NSArrayController -- which I do not recommend because it violates
encapsulation and leads people to mix model and controller level
code unnecessarily.
I. Savant suggested that you surround changes to docArray with
{will,did}ChangeValueForKey: pairs to ensure KVO change
notifications. I do not recommend this because it *also* violates
encapsulation -- you're mixing in "maintenance" code with the code
that uses the property. This is fragile in that it will be easy to
forget a spot, post the wrong notification due to a typo, etc.
So, since I've shot down the first two ideas posted, what *do* I
recommend? One of the following:
(1) Make your manipulations of the docArray property specific, by
implementing the appropriate ordered-relationship-KVC accessor
methods:
- (NSUInteger)countOfDocArray
- (id)objectInDocArrayAtIndex:(NSUInteger)index;
- (void)insertObject:(id)object inDocArrayAtIndex:(NSUInteger)index;
- (void)removeObjectFromDocArrayAtIndex:(NSUInteger)index;
And so on. The above four are the minimum methods to implement,
beyond -docArray and -setDocArray: -- the full naming pattern is
described in the Key-Value Coding Programming Guide, and it's also
documented in <Foundation/NSKeyValueCoding.h> under -valueForKey:
and -mutableArrayValueForKey:.
Then, instead of manipulating docArray directly, manipulate it only
using the above methods (which are allowed to manipulate the array
directly). Key-Value Observing -- used by bindings -- will
automatically do the right thing and cause the above methods to
post appropriate observer notifications for every manipulation of
the docArray property that occurs via them.
(2) Whether or not you do #1 above, you can just use the
NSMutableArray that you get back from [self
mutableArrayValueForKey:@"docArray"] to manipulate the array. It
will not actually return your own array; instead, it will return a
proxy object that also causes the appropriate KVO notifications to
be posted for every manipulation of your own array. If you *do* do
#1 above, it will even cause the methods you have written to be
invoked.
I'm sure this seems complicated -- "I just want to observe an
array!" you're no doubt saying -- but if you remember that
observation and (therefore) binding happens at the property rather
than the object level, it will make a lot more sense. As long as
you have the appropriate methods implemented for the type of
property you want to manipulate, and you manipulate the property
through those methods, its implementation will be irrelevant.
-- Chris
I have an example of my running into a similar problem and solving it
in a similar way. See items 29 through 32 here:
http://www.bagelturf.com/cocoa/rwok/rwok4/index.html
In my case I had an array of dictionaries whose elements were bound
to table columns. By implementing the methods that Chris describes in
(1) above, the magic (really just advanced technology) occurs and
changes are automatically seen and reflected in the interface.
The trick to understanding KVO is to realize that there is no such
thing as "observing" going on. "Observing" describes the effect
experienced, not the way the effect is implemented. As Chris points
out, it's the properties (via keys, as in *Key* Value Observing) that
are observed, not the objects themselves -- there is no Object
Observing.
KVO is an active process: changes to properties are actively
propagated to observers via messages. In the case of an array,
changing the members does nothing for an observer of the array
because the members are not actively involved in the observation.
Method (1) above provides for manipulation of the array by
implementing observable properties and hence the messages get to the
observers. Method (2) just hides all of that from you via a proxy
object.
_______________________________________________
Cocoa-dev mailing list (email@hidden)
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:
This email sent to email@hidden