I have a bit of code in my application that generates a Core Data Model and populates it with a set of NSEntityDescriptions. Each of these entity descriptions then have an arbitrary number of NSPropertyDescriptions allocated for them. These properties are a combination of NSAttributeDescriptions and NSRelationshipDescriptions. All relationships are matched with an existing relationship and they are set as inverse of one another using setInverseRelationship:.
The attribute properties work fine, and to-many relationships work fine; I have tested that thoroughly. The issue seems to be with NSRelationshipDescriptions that have a maxCount value of 1, meaning the property description returns a isToMany value of NO. When the inverseRelationship property is set for these type of relationship, Core Data crashes when I try to save any object that utilizes that relationship with the error:
2013-11-09 11:17:15.068 Directory[1344:5c03] -[NSManagedObject count]: unrecognized selector sent to instance 0x9643820
2013-11-09 11:17:15.074 Directory[1344:5c03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSManagedObject count]: unrecognized selector sent to instance 0x9643820'
*** First throw call stack:
(
0 CoreFoundation 0x01f9f5e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x01d228b6 objc_exception_throw + 44
2 CoreFoundation 0x0203c903 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
3 CoreFoundation 0x01f8f90b ___forwarding___ + 1019
4 CoreFoundation 0x01f8f4ee _CF_forwarding_prep_0 + 14
5 CoreData 0x0083c128 -[NSSQLCore _knownOrderKeyForObject:from:inverseToMany:] + 200
6 CoreData 0x00773080 -[NSSQLCore _populateRowForOp:withObject:] + 1120
7 CoreData 0x00789157 -[NSSQLCore recordValuesForInsertedObject:] + 71
8 CoreData 0x00771e8d -[NSSQLCore recordChangesInContext:] + 685
9 CoreData 0x00770c55 -[NSSQLCore saveChanges:] + 565
10 CoreData 0x0073d88c -[NSSQLCore executeRequest:withContext:error:] + 412
11 CoreData 0x0073d380 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 4704
12 CoreData 0x00769ffc -[NSManagedObjectContext save:] + 764
13 Directory 0x0002f2bf -[ETDatabaseController save] + 111
14 Directory 0x0002ba9c -[ETDataLoader performImportWithData:] + 10284
The insinuation I am gathering from this is it is considering the inverse relationship to be a to-many relationship when that is not the case. According to my assertions, what I know about each of my relationships is:
relationDescription.inverseRelationship != nil
[relationDescription.inverseRelationship.inverseRelationship isEqual:relationDescription]
I have tested this by creating the model and populating it with a small set of sample data. Currently, objects that have any sort of attributes, to-many relationships (with/without inverse), and to-one relationship (without inverse) work consistently. The issues comes when I try to have a to-one relationship with an inverse relationship.
This seems a bit convoluted so let me know if I need to clarify anything better. Thanks!
Edit 1:
The relationship creation is done in two steps, first it creates all the relationships, then it establishes the inverse of each relationship by using a lookup.
NSRelationshipDescription *description = [[NSRelationshipDescription alloc] init];
[description setName:self.name];
[description setDestinationEntity:entity];
[description setMaxCount:(isToMany ? 0 : 1)];
[description setMinCount:0];
[description setOrdered:YES]; // See you in a minute
later...
NSEntityDescription *inverseEntity = newRelationship.destinationEntity;
NSRelationshipDescription *inverseRelationDescription = [inverseEntity relationshipsByName][inverse.name];
if (inverseRelationDescription) {
inverseRelationDescription.inverseRelationship = newRelationship;
newRelationship.inverseRelationship = inverseRelationDescription;
} else if ([inverse.name isEqualToString:relation.name]) {
newRelationship.inverseRelationship = newRelationship;
}