Search code examples
iosobjective-ccocoa-touchcore-datarestkit

Can't map an array of objects for NSManagedObject in RestKit


I have User class which is NSManagedObject subclass:

@interface User : NSManagedObject

  @property (nonatomic, retain) NSString * about;
  @property (nonatomic, retain) NSString * contactAddress;
  @property (nonatomic, retain) NSString * contactEmail;
  @property (nonatomic, retain) NSString * hobbies;
  @property (nonatomic, retain) NSArray* jobExperience;
  @property (nonatomic, retain) NSString * name;
  @property (nonatomic, retain) NSString * surname;
@end

As you can see this object has an NSArray property of objects JobExperience. JobExperience defined as follows:

@interface JobExperience : NSObject <NSCoding>

 @property (nonatomic,strong) NSString* position;
 @property (nonatomic,strong) NSString* organization;
 @property (nonatomic,strong) NSString* dateFrom;
 @property (nonatomic,strong) NSString* dateTo;
 @property (nonatomic,strong) NSString* website;
 @property (nonatomic,strong) NSString* location;
 @property (nonatomic,strong) NSString* jobDescription;
@end

In the data model I have one entity User where jobExperience attribute defined as transformable. That's why I implement NSCoding methods in it. Here is my mapping for User:

 _sharedUserProfileMapping = [RKObjectMapping mappingForClass:[User class]];
    [_sharedUserProfileMapping addAttributeMappingsFromArray:@[
                                                               @"name", @"surname",
                                                               @"hobbies", @"interests",
                                                       @"contact_address", @"contact_email"
                                                              ]];

    RKObjectMapping* mappingForJobExperience = [RKObjectMapping mappingForClass:[JobExperience class]];
    [mappingForJobExperience addAttributeMappingsFromArray:@[
                                                             @"location",
                                                             @"website", @"organization" ,
                                                             @"position"  ,
                                                             @"date_from", @"date_to"
                                                             ]];

    [mappingForJobExperience addAttributeMappingsFromDictionary:@{@"description": @"jobDescription"}];

    [_sharedUserProfileMapping addRelationshipMappingWithSourceKeyPath:@"job_experience" mapping:mappingForJobExperience];

As you can see I add relationship mapping. When User was just an NSObject subclass all mapped perfectly!!! But when I made it NSManagedObject subclass I got an exception:

Mapping a to-many relationship for an NSManagedObject. About to apply value via mutable[Set|Array]ValueForKey restkit.object_mapping:RKMappingOperation.m:726 Mapped NSArray relationship object from keyPath 'job_experience' to 'jobExperience'. Value: ( "", "" ) * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'NSManagedObjects of entity 'User' do not support -mutableArrayValueForKey: for the property 'jobExperience'' * First throw call stack:

And just for clarifying other attributes map perfectly. The problem only with this array of JobExperience objects.


Solution

  • You could be falling into an area that isn't implemented here. An outer object with an array of managed objects works (IIRC), but from your description and outer managed object and an array of objects doesn't work. It doesn't help that you aren't actually showing the different mappings that do and don't work though...

    RestKit should be introspecting on the destination data type to decide what to do. Perhaps that doesn't work for this situation as it is provided with a relationship spec, it may assume that the destination is a Core Data relationship.

    In any case, it's unusual to have a managed object with an array of custom objects. Usually you would use 2 managed objects and a relationship between the entities. This makes more sense and provides more expressive power and efficiency at runtime. This is what I'd recommend.

    It could be that you need to set mappingForJobExperience.forceCollectionMapping = YES; to make it work (a guess).