Reputation: 1
I'm hoping someone can help me debugging an incredibly frustrating Core Data crash. I initially load data into two entities (representing 'speakers' and 'titles') I then load a third entity for 'sessions' and try to set relationships to 'speakers' and 'titles'. (from session to speaker and title is one-to-one. from speaker/title back to session is one-to-many). I use a integer key to set up each relationship.
Since a given speaker and title can point to multiple sessions, I wrote a function that searches for the appropriate managed object and returns the object. I then set it for the relationship.
This works fine for the speaker relationship but crashes consistently and horribly for the SECOND title. I've rewritten the code a couple of times in different ways and I always end up with the same problem. And the problem exists regardless of what title comes second. So I've gotta be doing something just fundamentally wrong but following along to the Core Data chapters in More iPhone 3 Development nothing jumps out to me. I'm hoping someone might see what I'm missing (and have been for days). (One last note: the crash occurs whether I save the managedObjectContext within the for loop or outside. Always on the second session). My endless thanks and first born child to whoever can help me with this.
Here's the relevent code that saves the session entity:
for (NSDictionary *session in self.sessions){
NSManagedObject *newSession = [NSEntityDescription insertNewObjectForEntityForName:[sessionEntity name] inManagedObjectContext:self.managedObjectContext];
[newSession setValue:[session valueForKey:@"ID"] forKey:@"id"];
[newSession setValue:[session valueForKey:@"notes"] forKey:@"notes"];
[newSession setValue:[session valueForKey:@"length"] forKey:@"length"];
//get the speaker value;
[newSession setValue:[self setupSpeaker:[session valueForKey:@"speaker"]] forKey:@"speaker"];
NSLog(@"now doing title");
//now get the title value;
[newSession setValue:[self setupTitle:[session valueForKey:@"title"]] forKey:@"title"];
NSLog(@"I got back this title:%@", [newSession valueForKey:@"title"]);
}
if (![self.managedObjectContext save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
Here's the code that finds the appropriate speaker and title entity for the relationship (I realize it's pretty redundant)
-(NSManagedObject *) setupSpeaker:(NSNumber *)id {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Speaker" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"id==%@",id];
[fetchRequest setPredicate:predicate];
NSError *error;
NSArray *items=[self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
if ([items count]>=1){
return [items objectAtIndex:0];
}else{
return 0;
}
}
-(NSManagedObject *) setupTitle:(NSNumber *)id {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Title" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSLog(@"now looking for: %@", id);
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"id==%@",id];
[fetchRequest setPredicate:predicate];
NSError *error;
NSArray *items=[self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
if ([items count]>=1){
NSLog(@"found %@", id);
return [items objectAtIndex:0];
}else{
return 0;
}
}
And finally here's what the logs says on crash:
2010-02-20 16:48:17.134 iconf[1438:207] now looking for: 1
2010-02-20 16:48:17.136 iconf[1438:207] found 1
2010-02-20 16:48:17.156 iconf[1438:207] I got back this title:<NSManagedObject: 0x3b11a10> (entity: Title; id: 0x3d4a3c0 <x-coredata://B76F62BD-AC82-4335-9013-7529C2471F9C/Title/p6> ; data: {
id = 1;
session = (
0x3d51640 <x-coredata:///Session/t2765697F-14C9-4282-A067-10A2413732B834>
);
title = "Bill Gates Speaks";
})
2010-02-20 16:48:17.158 iconf[1438:207] now doing title
2010-02-20 16:48:17.158 iconf[1438:207] now looking for: 2
2010-02-20 16:48:17.159 iconf[1438:207] found 2
2010-02-20 16:48:17.161 iconf[1438:207] I got back this title:<NSManagedObject: 0x3b16fd0> (entity: Title; id: 0x3d4d7a0 <x-coredata://B76F62BD-AC82-4335-9013-7529C2471F9C/Title/p12> ; data: {
id = 2;
session = (
0x3b1b320 <x-coredata:///Session/t2765697F-14C9-4282-A067-10A2413732B835>
);
title = "Lecture on Frogs";
})
2010-02-20 16:48:17.161 iconf[1438:207] *** -[NSManagedObject compare:]: unrecognized selector sent to instance 0x3b11a10
2010-02-20 16:48:17.162 iconf[1438:207] Serious application error. Exception was caught during Core Data change processing: *** -[NSManagedObject compare:]: unrecognized selector sent to instance 0x3b11a10 with userInfo (null)
2010-02-20 16:48:17.163 iconf[1438:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSManagedObject compare:]: unrecognized selector sent to instance 0x3b11a10'
2010-02-20 16:48:17.163 iconf[1438:207] Stack: (
Upvotes: 0
Views: 705
Reputation: 1640
Thanks, below is a copy of the data model. You are right about the basic layout.
http://www.freeimagehosting.net/image.php?debf5866c1.jpg
The reason I'm setting the relationships manually is because this is the first time through the program so I'm doing the initial load of data from three separate plists (one for speaker, one for title, one for session). Is there a better way to do this? I could be fundamentally not understanding core data but it seems as though if I just created a new title entity each time I created the session entity I'd have a one-to-one relationship from title to session rather than the one-to-many relationship that I want. Thus I put in the id variables (which I've now renamed with no change in the error) to act as a key for the first load into core data. After that I'd of course use core data to manage all that. Is there a better way to do this?
Upvotes: 0
Reputation: 21460
It sounds like your data model (should) look like this:
Speaker <-->> Session
Title <-->> Session
Where both Speaker and Title each have a to-many relationship to Session.
Based on this:
I use a integer key to set up each relationship.
and your code, it looks like you are managing the relationships manually. Why are you doing this?! It is complicated and unnecessary. Set up and use real relationships in your Core Data data model.
Also, do not use "id" for an attribute name since it is a keyword in objective-C.
Upvotes: 1