Core Data NSValidationErrorObject, causes crash
cocoa-touch, core-data, ios, objective-c
Solution
On a hunch: Is the relationship between objects in different MOCs? Strange things can happen if you do that!
Problem
I'm working on an app where I have Users, each User have a many-to-many relationship to followers. I'm currently having some problems with saving new user objects. The app craches on `managedObjectContext save`. I get the following error: ``` Unresolved error Error Domain=NSCocoaErrorDomain Code=1560 "The operation couldn’t be completed. (Cocoa error 1560.)" UserInfo=0x8580640 {NSDetailedErrors=( "Error Domain=NSCocoaErrorDomain Code=1550 \"The operation couldn\U2019t be completed. (Cocoa error 1550.)\" UserInfo=0x85820c0 {NSValidationErrorObject=<User: 0x7575870> (entity: User; id: 0x75757c0 NSValidationErrorKey=followers, NSLocalizedDescription=The operation couldn\U2019t be completed. (Cocoa error 1550.), NSValidationErrorValue=Relationship 'followers' on managed object (0x7575870) <User: 0x7575870> (entity: User; id: 0x75757c0 "Error Domain=NSCocoaErrorDomain Code=1550 \"The operation couldn\U2019t be completed. (Cocoa error 1550.)\" UserInfo=0x8586830 {NSValidationErrorObject=<User: 0x7571ec0> (entity: User; id: 0x7571f00 "Error Domain=NSCocoaErrorDomain Code=1550 \"The operation couldn\U2019t be completed. (Cocoa error 1550.)\" UserInfo=0x858e820 {NSValidationErrorObject=<User: 0x7573120> (entity: User; id: 0x7573160 [...] ``` I can't really figure out what is causing this crash. My relationship looks like this: The model have a custom NSManagedObject subclass with the `@property (nonatomic, retain) NSSet *followers;`. As I said, I'm not really sure what is causing this, so any guidance or ideas would be great! Update The app crashes in this method: ``` - (void)saveContext { NSError *error = nil; NSManagedObjectContext *managedObjectContext = self.managedObjectContext; [managedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy]; if (managedObjectContext != nil) { if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { // Replace this implementation with code to handle the error appropriately. // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. NSLog(@"Unresolved error %@, %@", error, [error userInfo]); // Uncomment "abort" makes it work, but I still get the error. abort(); } } } ``` Update 2 More code from my models and how it use them: How I set up my fetch request controller: ``` - (NSSortDescriptor *)sortDescriptorForFetchRequest { NSSortDescriptor *sortDescriptor; if ([self.postType isEqualToString:@"following"] || [self.postType isEqualToString:@"followers"]) { sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"userId" ascending:NO]; } else { sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"postId" ascending:NO]; } return sortDescriptor; } - (NSEntityDescription *)entityForFetchRequest { NSEntityDescription *entity; if ([self.postType isEqualToString:@"followers"] || [self.postType isEqualToString:@"following"]) { entity = [NSEntityDescription entityForName:@"User" inManagedObjectContext:[self.appController managedObjectContext]]; } else { entity = [NSEntityDescription entityForName:@"Post" inManagedObjectContext:[self.appController managedObjectContext]]; } return entity; } - (void)setUpFetchResultController { if (self.fetchedResultsController == nil) { NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; [fetchRequest setEntity:[self entityForFetchRequest]]; [fetchRequest setPredicate:[self predicateBasedOnPostType:self.postType]]; NSArray *sortDescriptors = @[[self sortDescriptorForFetchRequest]]; [fetchRequest setSortDescriptors:sortDescriptors]; self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[self.appController managedObjectContext] sectionNameKeyPath:nil cacheName:[self cacheName]]; self.fetchedResultsController.delegate = self; } } ``` And my model, `User`: ``` + (void)addUserFromDictionary:(NSDictionary *)dictionary forUser:(User *)user inManagedObjectContext:(NSManagedObjectContext*)moc follower:(BOOL)follower following: (BOOL)following { User *localUser; if (follower) { if ([dictionary isKindOfClass:[NSArray class]]) { NSEnumerator *enumerator = [dictionary objectEnumerator]; id value; while (value = [enumerator nextObject]) { localUser = [self parseUserFromDictionary:value inManagedObjectContext:moc]; if ([self user:localUser alreadyFollowingUser:user inManagedObjectContext:moc] == NO) { [user addFollowersObject:localUser]; [localUser addFollowingObject:user]; } } } } } + (User *)parseUserFromDictionary:(NSDictionary *)dictionary inManagedObjectContext:(NSManagedObjectContext*)moc { NSNumberFormatter *numberFormatter= [[NSNumberFormatter alloc] init]; NSNumber * userId = [numberFormatter numberFromString:(NSString *)[dictionary valueForKey:@"id"]]; User *user; if ([self userAlreadyExist:userId inManagedObjectContext:moc] == NO) { NSEntityDescription *userDescription = [NSEntityDescription entityForName:@"User" inManagedObjectContext:moc]; user = [[User alloc] initWithEntity:userDescription insertIntoManagedObjectContext:moc]; } else { user = [User findUser:userId inManagedObjectContext:moc]; } user.name = [dictionary valueForKey:@"name"]; [...] return user; } ```