Re: Fun (or not) with NSArrayControllers and CoreData.
Re: Fun (or not) with NSArrayControllers and CoreData.
- Subject: Re: Fun (or not) with NSArrayControllers and CoreData.
- From: Quincey Morris <email@hidden>
- Date: Wed, 29 Jul 2009 12:40:57 -0700
On Jul 29, 2009, at 11:27, Daniel DeCovnick wrote:
I read over the Ensuring KVO compliance docs, and I have to say, I
don't think I understand it. At first glance it looks fine to me,
but obviously it's not. Do I have to implement mutableSet/
ArrayValueForKey: myself, or am I completely on the wrong track?
Your NSManagedObject subclass Job, if I've got the naming right, has a
array property "allDescendentsJobs". The NSArrayController has as its
content array the *root* Job object. Therefore, the NSArrayController
is only going to get a KVO notification if the "allDescendentsJobs"
property of the *root* Job changes KVO-compliantly.
So ask: what is going to cause the "allDescendentsJobs" property of
the *root* Job to be updated KVO-compliantly? Answer: nothing, because
the property value is only created on demand (i.e. the first time the
NSArrayController refers to it), and thereafter the property is read-
only.
Getting KVO-compliant updates is hard in this situation. The root
level property is affected by every add/replace/remove change at every
lower level, which is potentially a lot of stuff to keep track of.
You're going to have to invent a strategy for changes at the lower
levels to inform the root level that something has changed, and for
the root level to manually trigger the KVO notification at the end of
a cycle of changes. (If you have implemented Undo, this is analogous
to the way individual property changes are batched into an undo group.)
It is feasible to trigger KVO notifications at lower levels and let
them percolate up naturally, but that of course will cause the
NSArrayController to be notified multiple times for what is
essentially a single change.
Probably it's going to be easier to solve if you promote
"allDescendentsJobs" into a read/write property (i.e. back it with a
NSMutableArray instance variable, or make it a Core Data transient
property -- in which case you'd be back to a set instead of an array,
and back to entity mode in the NSArrayController). Then, whenever you
add/remove/remove a Job node at any level, you'd also manually update
the root "allDescendentsJobs" property directly.
Note that this would still generate far too many KVO notifications for
the root object's "allDescendentsJobs" property, so you'd have to deal
with that. Also, you have to make sure the property is updated
properly on undo (which is why making it a transient Core Data
property is ultimately easier than using an instance variable, if
you're supporting undo, since you'd get that for free).
If you think this sounds complicated, you're right. (If anyone else
wants to jump in with an easier solution, I'd be happy to cede the
territory.)
Finally, one thing that helps with this problem is to give up on
trying to use KVO *on this property* to keep your user interface up-to-
date and write a data source delegate instead. If you have to keep
track of when the update is necessary, it's far easier to call
'reloadData' (and it doesn't hurt so bad to call that multiple times)
than to trick KVO into doing the right thing. Also (whew!),
NSOutlineView + NSTreeController + NSArrayController + KVO + undo is
reputed to have bugs, so you may do everything right and then have
your application crash after the user does an undo. (I've run into
this problem personally, but by the time you get there the
circumstances are so murky it's hard to know who to blame. But the
archives do claim this is a bug, and no one from Apple has denied it
AFAIK.)
Is that more information than you wanted? :)
P.S. If anyone else wants to jump in with an easier solution, I'd be
happy to cede the territory.
_______________________________________________
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