Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Duplicate Core Data objects created in RestKit 0.20.2

I'm running into an issue where I'm getting duplicate writes to my SQLite database every time I perform a mapping operation in RestKit 0.20.2. I've looked online pretty extensively and can't seem to find a duplicate issue to what I'm experiencing—all of the similar problems I've seen center around using RestKit for everything, while I'm using RestKit just for the mapping and database operations, as I'm doing the network aspect in another library.

I have a unique identificationAttribute property set (the tweet ID) and am using a managedObjectCache initialized with RKInMemoryManagedObjectCache; however, every time I perform a mapping operation, I'm getting duplicates across the board on everything. The library I'm using for the network side (STTwitter) returns the JSON as an array, so I iterate through each object in the array. Is there some other operation I'm supposed to be performing? I was under the impression that RestKit compares the identificationAttribute property specified in mapped objects to what's already in the SQLite database before doing any insertions. I wasn't encountering this issue when I used it for everything in another project, using RKManagedObjectRequestOperation.

Here's how I set up the model:

-(void)setup
{
self.objectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:[self managedObjectModel]];

[self.objectStore createPersistentStoreCoordinator];

NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"FoodTruckxxx.sqlite"];
NSLog(@"Setting up store at %@", path);
[self.objectStore addSQLitePersistentStoreAtPath:path
                          fromSeedDatabaseAtPath:nil
                               withConfiguration:nil
                                         options:self.optionsForSQLiteStore
                                           error:nil];

[self.objectStore createManagedObjectContexts];

self.objectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:self.objectStore.persistentStoreManagedObjectContext];
}

and here's how I perform the mapping operation:

-(void)performMapping
{
int i = 0;
while (i < self.localCopyOfAllStatuses.count)
{
    RKManagedObjectStore *store = [[FoodTruckDataModel sharedDataModel] objectStore];
    RKEntityMapping *mapping = [ObjectMappings FoodTruckArticleMapping];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"FoodTruck" inManagedObjectContext:store.persistentStoreManagedObjectContext];
    NSManagedObject *newManagedObject = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:store.persistentStoreManagedObjectContext];
    RKManagedObjectMappingOperationDataSource *mappingDS = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:store.persistentStoreManagedObjectContext cache:store.managedObjectCache];

    //assign new array to contain to just one object at a time and iterate through it
    NSArray *justOneStatus = [self.localCopyOfAllStatuses objectAtIndex:i];
    RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:justOneStatus destinationObject:newManagedObject mapping:mapping];
    operation.dataSource = mappingDS;
    NSError *error = nil;
    [operation performMapping:&error];
    [store.persistentStoreManagedObjectContext save:&error];
    [store.persistentStoreManagedObjectContext saveToPersistentStore:&error];
    i++;
}
}

And here is the mapping:

+(RKEntityMapping *)FoodTruckArticleMapping
{
RKEntityMapping *jsonMapping = [RKEntityMapping mappingForEntityForName:@"FoodTruck" inManagedObjectStore:[[FoodTruckDataModel sharedDataModel] objectStore]];
jsonMapping.identificationAttributes = @[@"tweetID"];

[jsonMapping addAttributeMappingsFromDictionary:@{
 @"text": @"tweet", @"user.screen_name": @"foodTruckName", @"created_at": @"timeStamp", @"id": @"tweetID"}];

return jsonMapping;
}

And here is a complete operation from my log. Any help would be greatly appreciated!

like image 465
Evan R Avatar asked Jun 30 '26 14:06

Evan R


1 Answers

Per the answer to this question on the RestKit Google Group board (which I verified worked), the solution was to not create a NSManagedObject and to assign nil to destinationObject in my RKMappingOperation declaration. Below is the correct code for this method, and the answer to my initial question:

-(void)performMapping
{
    int i = 0;
    while (i < self.localCopyOfAllStatuses.count)
    {
        RKManagedObjectStore *store = [[FoodTruckDataModel sharedDataModel] objectStore];
        RKEntityMapping *mapping = [ObjectMappings FoodTruckArticleMapping];
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"FoodTruck" inManagedObjectContext:store.persistentStoreManagedObjectContext];
        RKManagedObjectMappingOperationDataSource *mappingDS = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:store.persistentStoreManagedObjectContext cache:store.managedObjectCache];

        //assign new array to contain to just one object at a time and iterate through it
        NSArray *justOneStatus = [self.localCopyOfAllStatuses objectAtIndex:i];
        RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:justOneStatus destinationObject:nil mapping:mapping];
        operation.dataSource = mappingDS;
        NSError *error = nil;
        [operation performMapping:&error];
        [store.persistentStoreManagedObjectContext save:&error];
        [store.persistentStoreManagedObjectContext saveToPersistentStore:&error];
        i++;
    }
}

However, it was also suggested in the RestKit Google Group link that I implement RKMapperOperation instead of RKMappingOperation, as it then saves me the trouble of iterating through my array of JSON responses. This is what I eventually went with, which I present for the sake of efficiency and better use of RestKit:

-(void)performMapping
{
    RKManagedObjectStore *store = [[FoodTruckDataModel sharedDataModel] objectStore];
    RKManagedObjectMappingOperationDataSource *mappingDS = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:store.persistentStoreManagedObjectContext cache:store.managedObjectCache];
    RKMapperOperation *mapperOperation = [[RKMapperOperation alloc] initWithRepresentation:self.localCopyOfAllStatuses mappingsDictionary:@{ [NSNull null]: [ObjectMappings FoodTruckArticleMapping] }];
    mapperOperation.mappingOperationDataSource = mappingDS;
    NSError *error = nil;
    [mapperOperation execute:&error];
    [store.persistentStoreManagedObjectContext save:&error];
    [store.persistentStoreManagedObjectContext saveToPersistentStore:&error];
}
like image 82
Evan R Avatar answered Jul 02 '26 02:07

Evan R



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!