views:

1966

answers:

6

Hello everyone, I have come to a roadblock in my current project. I basically have an app that is much like the Core Data Recipe app... Here is the basic structure I have in my .xcdatamodel

Entity: Restaurant String: name Category: category <---- to-many relationship

Entity: Category String: name Restaurant: restaurant <---- to-many relationship So basically, a Restaurant can have multiple categories... And there are a const number of predefined Categories.. For example: Restaurant: Name: Chili’s Categories: Take Out , Family Dining

“Take Out” and “Family Dining” are 2 of 10 different possible Restaurant Categories. How do I go about doing this.. I have looked at the sqllite database and I have my ZRestaurant and ZCategory table + the join table for both of them... I have data in both...

How do I go about setting my Restaurants Catagory with the different values? and then how do I fetch them back?

Thanks all! Kurt

A: 

How do I go about setting my Restaurants Catagory with the different values? and then how do I fetch them back?

The best thing to do is go through the Core Data Tutorial for iPhone, which goes through how to add new managed object instances of an Entity type (in your case, "Restaurant"), set that instance's attributes (e.g., "Restaurant.category") and fetch results.

The tutorial uses an Entity type called "Event" which has date and location attributes, but the ideas are all the same.

Alex Reynolds
A: 

Thank you Alex for the quick response. I have actually read through all the Core Data docs on the apple web site and I have studied thoroughly the different sample projects...

Here is a little of what I have

@interface Restaurant : NSManagedObject {
}
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSSet* catagory;

------------------
...
...
...
NSManagedObject newCatagory;    
NSManagedObjectContext *context = [restaurant managedObjectContext];
[newCatagory setValue:@"Drive Thru to Go" forKey:@"name"] ;
[restaurant addCatagoryObject:newCatagory];
...
...

I get a runtime error.. 2009-09-19 16:37:37.662 MyDine[25654:207] * -[Restaurant addCatagoryObject:]: unrecognized selector sent to instance 0x1027300 2009-09-19 16:37:37.662 MyDine[25654:207] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[Restaurant addCatagoryObject:]: unrecognized selector sent to instance 0x1027300'

Kurt
A: 

You would want to do something like this, instead:

Restaurant *mcDonalds = (Restaurant *)[NSEntityDescription insertNewObjectForEntityForName:@"Restaurant" inManagedObjectContext:managedObjectContext];
mcDonalds.name = @"McDonalds";

Restaurant *inNOut = (Restaurant *)[NSEntityDescription insertNewObjectForEntityForName:@"Restaurant" inManagedObjectContext:managedObjectContext];
inNOut.name = @"In-N-Out";

Category *driveThru = (Category *)[NSEntityDescription insertNewObjectForEntityForName:@"Category" inManagedObjectContext:managedObjectContext];
driveThru.name = @"Drive Thru to Go";

Category *sitDown = (Category *)[NSEntityDescription insertNewObjectForEntityForName:@"Category" inManagedObjectContext:managedObjectContext];
sitDown.name = @"Sit Down and Eat";

// make NSSet* of Category objects
NSSet *fastFood = [NSSet setWithObjects:driveThru, sitDown, nil];

// set Restaurant instances' categories ("to-many") property
mcDonalds.categories = fastFood;
inNOut.categories = fastFood;

// save changes to managedObjectContext...
NSError *error = nil;
if ([managedObjectContext save:&error]) {
   // handle save error
}

You're not instantiating your Category managed object correctly, and you want to learn how to use the accessors. Once you have done that, you will be better able to learn how to do fetches.

Honestly, I would recommend putting your project to the side and going through the Core Data Tutorial for iPhone.

Alex Reynolds
A: 

Alex thank you very much.. I really appreciate the help.. the problem with the core data tutorial it does not help at all with the to-many or many-to-many relationships... (at least I have not seen it in there)

In my Restaurant Class the catagory is defined as a NSSet* so doing a simple .catagory is not allowed (compiler warning) /Users/Kurt/Desktop/Classes/EditCategoriesTableViewController.m:80:0 /Users/Kurt/Desktop/Classes/EditCategoriesTableViewController.m:80: warning: incompatible Objective-C types 'struct Category *', expected 'struct NSSet *' when passing argument 1 of 'setCategory:' from distinct Objective-C type

I do notice the Restaurant (since it is an NSManagedObject) has

- (void)addCategoryObject:(NSManagedObject *)value 
{    
    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];

    [self willChangeValueForKey:@"category" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];
    [[self primitiveCatagory] addObject:value];
    [self didChangeValueForKey:@"category" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];

    [changedObjects release];
}

So I tried that, but it has a runtime error at the addObject:value.. sigh

Again I really appreciate all the help.. Thank you so much! -Kurt

Kurt
Just instantiate your `Category` instances, add them to an `NSSet` called `myCategorySet`, and then call `[myRestaurant addCategories:myCategorySet]` or `myRestaurant.categories = myCategorySet`.
Alex Reynolds
See my edited example to see how you would do a to-many categories assignment.
Alex Reynolds
Thank you Alex, much appreciated... Things are still not working so I am sure I have something wrong somewhere else. I am able to get it working with only 1 catagory but when ever I move to more then 1 I keep getting a runtime error.. I will get back to this once I figure out what is wrong with my code.. again much thanks!
Kurt
+1  A: 

If you want to call a method like "-addCatagoryObject:" on your NSManagedObject subclass, you have to have the code for that method in your actual .m file - it is NOT generated at runtime.

HOWEVER, it can be generated for you semi-automatically by Xcode - look for the various menu items that allow you to copy method definitions and implementations in Xcode.

Most people skip these nowadays, you don't NEED to call -addCategoryObject:, you can just let the runtime generate accessor code for you.

First off, your variable name (in the header and in your model) should be "categories", not "category", since it's representing a set, not a singleton.

You can then set categories to any set you want, using something like:

restaurant.categories = [NSSet setWithObjects:category1, category2, nil];
Wil Shipley
Thank you Will for the response.. I think my issue might be something somewhere else in my code.. because this still is not working, I am looking at my SQLLite db and I cannot get any data to show up or be associated with my restaurant in the join table. I will post back once I figure that out. Thank you so much!
Kurt
+1  A: 

OK, After working on this for the past 2 days I finally came up with my solution which was actually a mix between Alex and Wills suggestions... Thank you to both of you!!

Here is what I have...

 NSManagedObjectContext *context = [restaurant managedObjectContext];


NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"Category" inManagedObjectContext:context]];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:&sortDescriptor count:1];
[fetchRequest setSortDescriptors:sortDescriptors];

NSError *error = nil;
NSArray *possibleCategories = [context executeFetchRequest:fetchRequest error:&error];

categoryArray = [[NSMutableArray alloc] initWithArray:possibleCategories];

currentCategories = [restaurant valueForKeyPath:@"categories"];

[restaurant addCategoriesObject:(Category *)[possibleCategories objectAtIndex:15 ]];

[currentCategories addObject:(Category*)[categoryArray objectAtIndex:15]];

and then I save like this

- (void)save{
NSLog(@"EditCatagoriesTableViewController - save");

NSSet* myCategorySet = [[NSSet alloc] initWithSet:currentCategories];

NSError *error = nil;

[restaurant addCategories:myCategorySet];


error = nil;
if (![restaurant.managedObjectContext save:&error]) {
 // Handle error
 NSLog(@"restaurant - Unresolved error %@, %@", error, [error userInfo]);
 exit(-1);  // Fail
}

}

And that does it!

Thank you so much for the help you two!!!

-Kurt

Kurt