small medium large xlarge

Back to: All Forums  Core Data
04 Feb 2009, 04:18
Luc Vandal (1 post)

Hi. Great book so far! Will you be covering how to alter an array content programmatically? When calling addObject the views are not automatically refreshed and I’m having a hard time understanding how to use mutableArrayValueForKey and other related methods.


07 Feb 2009, 03:30
Marcus S. Zarra (284 posts)

The views should be updating automatically. I would suggest looking at your @NSArrayController@ settings and make sure “Prepares Content” is checked. The KVO should detect that the relationship has changed and update the display accordingly.

As for @-mutableArrayValueForKey:@, that is not part of Core Data but is part of KVC. You should be using @-mutableSetValueForKey:@ when dealing with @NSManagedObject@ objects.

26 Mar 2009, 16:26
Matthias Steffens (1 post)

Hi, w.r.t. -mutableSetValueForKey:, I got a bit confused by reading about -mutableSetForKey: on pages 54+55 of your eBook (beta 4), until I figured this was probably just a typo and should instead read -mutableSetValueForKey:. Thanks for your efforts! Matthias

29 Mar 2009, 17:33
Marcus S. Zarra (284 posts)

Thank you for catching that. I have corrected it for the next release.

BTW, if you find something like this in the future it would be helpful to file it in the errata section. That guarantees that it will be caught and fixed. It’s like a bug tracker for the book :)

Thanks again!

16 Sep 2009, 03:23
Johann Köbbe (13 posts)

I was experiencing a bit of trouble with mutableSetValueForKey as well.

On page 58 of b6, it is written:

bq. Note that we did not need to set the NSMutableSet back into the Recipe entity and therefore the code to add an object to a To-Many relationship is quite short.

I did not find that to work, though. I had this code:

	NSArray* target_objects = [target_array_controller arrangedObjects];
	NSManagedObject* target = [target_objects objectAtIndex: row];
	NSMutableSet* target_verses = [target mutableSetValueForKey: @"verses"];
	NSPasteboard* pasteboard = [info draggingPasteboard];
	NSData* row_data = [pasteboard dataForType: MyPrivateTableViewDataType];
	NSIndexSet* row_indexes = [NSKeyedUnarchiver unarchiveObjectWithData: row_data];

	NSManagedObject* verse;
	NSUInteger drag_row = [row_indexes firstIndex];
	while (drag_row != NSNotFound)
		verse = [verses objectAtIndex: drag_row];
		[target_verses addObject: verse];
		drag_row = [row_indexes indexGreaterThanIndex: drag_row];

It’s some drag and drop stuff to assign an item to either a list or a tag, depending on which table view is the drop target. Notice that target_verses is assigned the result of [target mutableSetValueForKey: @"verses"] and in the while loop I did [target_verses addObject: verse], but the relationship was not created (I checked by looking in the data). When I added [target setValue: target_verses forKey: @"verses"] immediately after the addObject call, then the relationship was persisted as expected.

I checked the array controller in the xib and it is set to “Prepares Content”. This is on Snow Leopard 10.6.1, XCode 3.2, and IB 3.2 (732). Any ideas?


20 Sep 2009, 14:58
Marcus S. Zarra (284 posts)

Is the relationship bi-directional?

23 Sep 2009, 13:29
Johann Köbbe (13 posts)

Yes, the relationship is bi-directional. As I was verifying the inverse relationships, I got to thinking about what I’m doing and realized I need to provide a bit more information.

I have three entities: List, Tag, and Verse. List and Tag each have an optional, to-many relationship to Verse. Verse has two optional, to-many, inverse relationships to List and Tag. The idea is a verse can be assigned to zero or more lists or tags, so a list or tag can have zero or more verses.

In the code I showed above, I left out the part that defined target_array_controller. It is:

- (BOOL) tableView: (NSTableView *) tableView acceptDrop: (id <NSDraggingInfo>) info
	row: (NSInteger) row dropOperation: (NSTableViewDropOperation) dropOperation
	NSArrayController* target_array_controller = [tableView isEqualTo: lists_table_view] ? lists_array_controller : tags_array_controller;

Depending on which table view is the drop target, I use the corresponding array controller to access the appropriate collection of objects to find the specific one that the verse was dropped on, hence target and target_verses in the posted code.

I obviously didn’t think this approach would be a problem, but now that I think about it, I’m not so sure. Does anyone reading this see any potential or real problems?

23 Sep 2009, 13:52
Johann Köbbe (13 posts)

I cannot explain why, but the code is working correctly now as you had it in the book. I commented out

	[target setValue: target_verses forKey: @"verses"];

and the relationship is being persisted. I have made a number of little changes here and there, so I have no idea if something I did had an effect or not.

Oh well. I don’t like it when things suddenly start working for no apparent reason, but I do like the fact that they are working.

You must be logged in to comment