Re: Core-data binding to all entities
Re: Core-data binding to all entities
- Subject: Re: Core-data binding to all entities
- From: Brent Gulanowski <email@hidden>
- Date: Sun, 4 Oct 2009 16:05:20 -0400
On Fri, Oct 2, 2009 at 2:39 AM, Martin Hewitson
<email@hidden>wrote:
> Dear list,
>
> I have a simple core-data model with an entity 'Category' and an entity
> 'Note'. The 'Category' entity has a to-many relationship 'notes' to entity
> type 'Note'.
>
> The categories are displayed in an outline view via a tree controller.
> There is also a table which displays the contents of an array controller
> (NotesArrayController) - this is supposed to show a subset of the notes.
>
> I have a switch on the UI which is meant to let the user choose whether to
> display all notes in the currently selected category, or all notes from all
> categories. So I want to modify the content of NotesArrayController
> depending on the state of the switch.
>
> So far I tried doing this programatically with bindings using the two
> methods below (actually the switching mechanism is just two buttons). This
> works as far as displaying the correct content to the user, but when it
> comes to deleting objects when in 'all categories' mode, it doesn't work
> properly. I get messages in the console like:
>
> *** -[NSCFArray removeObjectAtIndex:]: mutating method sent to immutable
> object
>
> So that's pretty clear, and I'm obviously going about this in the wrong
> way. The question is, what is a proper way to handle this?
>
> Thanks in advance for any constructive comments,
>
> Martin
>
>
> #pragma mark -
> #pragma mark Category control
>
> - (IBAction)allCategoriesSelected:(id)sender
> {
> [singleCategoryButton setState:0];
> [allCategoriesButton setState:1];
>
> [notesArrayController unbind:@"contentSet"];
> [notesArrayController unbind:@"contentArrayForMultipleSelection"];
> [notesArrayController setContent:nil];
>
> NSManagedObjectContext *moc = managedObjectContext;
> NSFetchRequest *request = [[NSFetchRequest alloc] init];
> [request setEntity:[NSEntityDescription entityForName:@"Note"
> inManagedObjectContext:moc]];
> NSError *error = nil;
> NSArray *results = [moc executeFetchRequest:request error:&error];
> if (error) {
> [NSApp presentError:error];
> [request release];
> return;
> }
>
> [notesArrayController setContent:results];
> [request release];
>
> }
>
> - (IBAction)singleCategorySelected:(id)sender
> {
> [allCategoriesButton setState:0];
> [singleCategoryButton setState:1];
>
> [notesArrayController unbind:@"contentSet"];
> [notesArrayController unbind:@"contentArrayForMultipleSelection"];
> [notesArrayController setContent:nil];
>
> NSDictionary *dict = [NSDictionary dictionaryWithObject:[NSNumber
> numberWithBool:YES]
>
> forKey:NSDeletesObjectsOnRemoveBindingsOption];
>
> // bind contents to entries in the selected categories
> [notesArrayController bind:@"contentSet"
> toObject:treeController
> withKeyPath:@"selection.notes" options:dict];
>
> // so that multiple selected categories works properly but this is
> not really
> // necessary since we don't allow multiple selection on the outline
> view at the
> // moment.
> [notesArrayController bind:@"contentArrayForMultipleSelection"
> toObject:treeController
> withKeyPath:@"email@hidden
> "
> options:nil];
> }
>
>
The problem you're experiencing is two-fold. First, the error is because
you're setting the array controller's content with an immutable array, so
you can't modify that array. However, that's not your real problem.
Even if you made that array mutable, that array has no real connection with
your underlying data store. Well, I should be careful here. If you have your
controller configured correctly, it might very well work to create and
delete persistent objects even if the array controller did not prepare its
own content. But this approach is unorthodox (at least to me). But you're
doing more work than you need to.
Most of this work can be done automatically by taking advantage of the array
controller's filterPredicate binding, conveniently available right from
Interface Builder. What you can do is to configure the array controller for
your note entity and set it to prepare its own content. Then create a
property on one of your controller classes (either your document or app
delegate, for example) to return a predicate that you will change depending
on the currently selected state of your all/category button. Ensure that
that property is KVO-compliant. Then bind the array controller's
filterPredicate to that property.
When you update the predicate, the array controller should filter its own
content automatically. No need for you to fetch the objects yourself or to
ever invoke -setContent on the array controller.
Cheers,
--
Brent Gulanowski
_______________________________________________
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