Search code examples
iosobjective-crestkit

RestKit one-to-many relationship doesn't have the correct number of objects after mapping JSON response


I have an NSManagedObject subclass TAGRemoteObject

TAGRemoteObject.h

extern const struct TAGRemoteObjectAttributes {
    __unsafe_unretained NSString *object_Id;
} TAGRemoteObjectAttributes;

@interface TAGRemoteObject ()

@property (nonatomic, strong) NSString *object_Id;

@end

TAGRemoteObject.m

const struct TAGRemoteObjectAttributes TAGRemoteObjectAttributes = {
    .object_Id = @"object_Id",
};

@implementation TAGRemoteObject

@dynamic object_Id;

+(RKEntityMapping*)entityMappingInManagedObjectStore:(RKManagedObjectStore *)managedObjectStore
{
   RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([self class]) inManagedObjectStore:managedObjectStore];

    [entityMapping addAttributeMappingsFromDictionary:@{
                                                        @"object_id" : TAGRemoteObjectAttributes.object_Id,
                                                        }];

    [entityMapping setIdentificationAttributes:@[ TAGRemoteObjectAttributes.object_Id ]];

    return entityMapping;
}

@end

Then I have two subclasses of TAGRemoteObject. TAGPost has a one-to-many viewedUsers relationship to TAGUser. TAGUser also has a one-to-many posts relationship to TAGPost.

TAGPost.h

extern const struct TAGPostRelationships {
    __unsafe_unretained NSString *viewedUsers;
} TAGPostRelationships;

@interface TAGPost : TAGRemoteObject ()

@property (nonatomic, strong) NSSet *viewedUsers;

@end

TAGPost.m

const struct TAGPostRelationships TAGPostRelationships = {
    .viewedUsers = @"viewedUsers",
};

@implementation TAGPost

@dynamic viewedUsers;

+(RKEntityMapping*)entityMappingInManagedObjectStore:(RKManagedObjectStore *)managedObjectStore
{
    RKEntityMapping *entityMapping = [super entityMappingInManagedObjectStore:managedObjectStore];

    RKEntityMapping *userMapping = [TAGUser entityMappingInManagedObjectStore:managedObjectStore];

    RKRelationshipMapping *viewedUsersMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"viewed_users" toKeyPath:TAGJourneyOutgoingPostRelationships.viewedUsers withMapping:userMapping];
    viewedUsersMapping.assignmentPolicy = RKUnionAssignmentPolicy;
    [entityMapping addPropertyMapping:viewedUsersMapping];

    return entityMapping;
}

@end

TAGUser.h

extern const struct TAGUserAttributes {
    __unsafe_unretained NSString *username;
} TAGUserAttributes;

extern const struct TAGUserRelationships {
    __unsafe_unretained NSString *posts;
}

@interface TAGUser : TAGRemoteObject ()

@property (nonatomic, strong) NSString *username;
@property (nonatomic, strong) NSSet *posts;

@end

TAGUser.m

const struct TAGUserAttributes TAGUserAttributes = {
    .username = @"username",
};

const struct TAGUserRelationships TAGUserRelationships = {
    .posts = @"posts",
};

@implementation TAGUser

@dynamic username;
@dynamic posts;

+(RKEntityMapping*)entityMappingInManagedObjectStore:(RKManagedObjectStore *)managedObjectStore
{
    RKEntityMapping *entityMapping = [super entityMappingInManagedObjectStore:managedObjectStore];

    [entityMapping addAttributeMappingsFromDictionary:@{
                                                        @"username" : TAGUserAttributes.username,
                                                        }];

    RKEntityMapping *postEntityMapping = [TAGPost entityMappingInManagedObjectStore:managedObjectStore];

    RKRelationshipMapping *postsRelationshipMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:@"posts" toKeyPath:TAGUserRelationships.posts withMapping:postEntityMapping];
    postsRelationshipMapping.assignmentPolicy = RKUnionAssignmentPolicy;
    [entityMapping addPropertyMapping:postsRelationshipMapping];

    return entityMapping;
}

@end

The issue I'm having is that when I receive a JSON response like this for the home feed which has many users, I get a viewedUsers.count of 3 which is expected:

{
    "error": null,
    "result": [
        {
            "object_id": 1,
            "username": "a",
            "posts": [
                {
                    "object_id": 299,
                    "viewed_users": [
                        {
                            "object_id": 3,
                            "username": "b"
                        },
                        {
                            "object_id": 4,
                            "username": "b"
                        },
                        {
                            "object_id": 5,
                            "username": "b"
                        }
                    ]
                }
            ]
        }
    ]
}

But when I send a request for all the posts for user 1 and get the following response, viewedUsers.count is either 0 or 1 randomly for every post:

{
    "error": null,
    "result": [
        {
            "object_id": 299,
            "viewed_users": [
                {
                    "object_id": 3,
                    "username": "b"
                },
                {
                    "object_id": 4,
                    "username": "b"
                },
                {
                    "object_id": 5,
                    "username": "b"
                }
            ]
        },
        {
            "object_id": 300,
            "viewed_users": [
                {
                    "object_id": 3,
                    "username": "b"
                },
                {
                    "object_id": 4,
                    "username": "b"
                }
            ]
        },
        {
            "object_id": 301,
            "viewed_users": [
                {
                    "object_id": 3,
                    "username": "b"
                },
                {
                    "object_id": 4,
                    "username": "b"
                },
                {
                    "object_id": 5,
                    "username": "b"
                }
            ]
        }
    ]
}

When I send the request to homefeed, I map to [TAGUser entityMappingInManagedObjectStore:self.objectManager.managedObjectStore];

When I send a request to get the posts for the user, I map to [TAGPost entityMappingInManagedObjectStore:self.objectManager.managedObjectStore];

I'm really lost as to why the mapping just doesn't work sometimes. When I set RestKit's logging level to RKLogLevelTrace, it sees the JSON array of length 3, but after mapping, the relationship only has 0 or 1.

Edit: I suspected that the circular relationship might be the issue, so I removed the posts relationship from the TAGUser mapping. I'm still seeing the issue though.


Solution

  • Turns out the relationship was set to one-to-many, when it should have been set to many-to-many.