Paulo Rodrigues
Paulo Rodrigues

Reputation: 5303

Saving one-to-many relationship CoreData

I am having troubles with the relationship I have setup in CoreData. Its one to many, a Customer can have many Contact, these contacts are from address book.

My model it looks like this:

Customer <---->> Contact
Contact  <-----> Customer

Contact.h

@class Customer;

@interface Contact : NSManagedObject

@property (nonatomic, retain) id addressBookId;
@property (nonatomic, retain) Customer *customer;

@end

Customer.h

@class Contact;

@interface Customer : NSManagedObject

@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSSet *contact;

@end

@interface Customer (CoreDataGeneratedAccessors)

- (void)addContactObject:(Contact *)value;
- (void)removeContactObject:(Contact *)value;
- (void)addContact:(NSSet *)values;
- (void)removeContact:(NSSet *)values;

@end

And trying save with:

AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
Customer *customer = (Customer *)[NSEntityDescription insertNewObjectForEntityForName:@"Customer" inManagedObjectContext:context];

[customer setValue:name forKey:@"name"];

for (id contact in contacts) {
    ABRecordRef ref = (__bridge ABRecordRef)(contact);
    Contact *contact = [NSEntityDescription insertNewObjectForEntityForName:@"Contact" inManagedObjectContext:context];

    [contact setValue:(__bridge id)(ref) forKey:@"addressBookId"];
    [customer addContactObject:contact];
}

NSError *error;

if ([context save:&error]) { // <----------- ERROR
    // ...
}

With my code, I have this error:

-[__NSCFType encodeWithCoder:]: unrecognized selector sent to instance 0x9c840c0
*** -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFType encodeWithCoder:]: unrecognized selector sent to instance 0x9c840c0'

Any suggestions would be appreciated.

Upvotes: 0

Views: 1146

Answers (1)

Tom Harrington
Tom Harrington

Reputation: 70936

The problem is that addressBookId is (as you mentioned in a comment) defined as a transformable attribute on the Contact entity. However (as you also mentioned in a comment) you don't have any custom code to actually transform an ABRecordRef into something that Core Data knows how to store. With no custom transformer, Core Data is going to try and transform the value by calling encodeWithCoder: on the value. But ABRecordRef doesn't conform to NSCoding, so this fails and your app crashes.

If you want to store the ABRecordRef in Core Data, you'll need to create an NSValueTransformer subclass and configure that in your data model. Your transformer would need to convert ABRecordRef into one of the types Core Data knows. I haven't worked with the address book API enough to advise on the details of this, but Apple documents NSValueTransformer pretty well.

The fact that it's a one-to-many relationship is irrelevant; the problem is that ABRecordRef can't go into your data store without some transformation.

Upvotes: 3

Related Questions