tarheel
tarheel

Reputation: 4797

Core Data app crashing when using setValue:forKey: for many-to-many relationship

I have gone over this over and over, and cannot for the life of me figure out why assigning a relationship through setValue:forKey: is not working. My method is below.

-(void)saveNewCartItemName:(NSString *)name Price:(float)price Qty:(int)qty Tax:(int)tax inCart:(NSDate *)cartDate{
    NSManagedObject *newItem = [NSEntityDescription insertNewObjectForEntityForName:@"Item"
                                                             inManagedObjectContext:self.appDelegate.managedObjectContext];

    NSFetchRequest *query = [[NSFetchRequest alloc] initWithEntityName:@"Cart"];
    NSLog(@"cartDate = %@", cartDate);
    [query setPredicate:[NSPredicate predicateWithFormat:@"cartDate = %@", cartDate]];
    NSError *error;
    NSMutableArray *queryResults = [[self.appDelegate.managedObjectContext executeFetchRequest:query error:&error] mutableCopy];
    NSLog(@"queryResults count = %d", [queryResults count]);
    if ([queryResults count] == 1) [newItem setValue:[queryResults objectAtIndex:0] forKey:@"cartThatHasItem"];
    [newItem setValue:name forKey:@"itemName"];
    [newItem setValue:[NSNumber numberWithFloat:price] forKey:@"itemPrice"];
    [newItem setValue:[NSNumber numberWithInt:qty] forKey:@"itemQty"];
    [newItem setValue:[NSNumber numberWithInt:tax] forKey:@"itemTax"];

    [self.appDelegate.managedObjectContext save:&error];
}

The line that it crashes on every time is:

if ([queryResults count] == 1) [newItem setValue:[queryResults objectAtIndex:0] forKey:@"cartThatHasItem"];

My NSLog shows that there is a NSManagedObject to assign the relationship to, and I have double checked the name in the forKey: that there are no typos. All that Xcode tells me is that it prints out '(null)' on my console and then tells me 'libc++abi.dylib: terminate called throwing an exception' on the next line.

Why is it crashing? And how do I fix it?

Update: That's the entire error message.

2012-07-03 18:28:57.844 appName[3063:11603] (null)
libc++abi.dylib: terminate called throwing an exception
(lldb)

Upvotes: 0

Views: 2372

Answers (2)

Cliff Ribaudo
Cliff Ribaudo

Reputation: 9039

One problem I see is that your not checking the error object. If an error occurs then queryResults will likely be = nil and you subsequent attempt to check count is going to crash you. At the very least check for the nil condition:

NSMutableArray *queryResults = [[self.appDelegate.managedObjectContext executeFetchRequest:query error:&error] mutableCopy];

if( queryResults == nil ) return; // Or better yet check the value of Error.

Upvotes: 1

Kjuly
Kjuly

Reputation: 35171

Well, no enough debug info... Cause you only need to check whether queryResults has an object, so I will use

[newItem setValue:[queryResults lastObject] forKey:@"cartThatHasItem"];

instead of

if ([queryResults count] == 1) [newItem setValue:[queryResults objectAtIndex:0] forKey:@"cartThatHasItem"];

Not sure whether it'll solve your issue, but worth trying. :)


EDIT

Through your question title '... for many-to-many relationship', I wonder what's the relationship between cartThatHasItem & Cart? If it is many to one or many to many, then the cartThatHasItem's data type will be NSSet. So, you need to wrap the [queryResults objectAtIndex:0]' like

[newItem setValue:[NSSet setWithObject:[queryResults objectAtIndex:0]]
           forKey:@"cartThatHasItem"];

, or you can use

[newItem addCartThatHasItem:[queryResults objectAtIndex:0]]

instead. (addCartThatHasItem: will be added automatically when you generate your Cart model.)


EDIT 2

The Cart model should be like this:

@interface Cart : NSManagedObject

//...
@property (nonatomic, retain) NSSet *cartThatHasItem;

@end

@interface Cart (CoreDataGeneratedAccessors)

//...
- (void)addCartThatHasItemObject:(CartThatHasItem *)value;
- (void)removeCartThatHasItemObject:(CartThatHasItem *)value;
- (void)addCartThatHasItem:(NSSet *)values;
- (void)removeCartThatHasItem:(NSSet *)values;

@end

if you generate your model correctly.

Upvotes: 1

Related Questions