I am using Azure Mobile Service as a backend for an iOS application. I have set up everything to work with offline sync which allows me to view, add, or modify data even when there is no network connection. I am running into a problem when I add a new object into a table. The add works well locally but when I synchronize data it creates a duplicate item on the local database with a slightly different objectId. The created item is not duplicated on the server side.
Here's how I am setup. By the way, thanks to @TheBasicMind for posting this model.
Here's a link to his explanation of the model: enter link description here
Here's what I do to setup the sync context and sync table:
// Initialize the Mobile Service client with your URL and key
MSClient *client = self.hpc.client;
NSManagedObjectContext *context = self.hpc.syncContext;
MSCoreDataStore *store = [[MSCoreDataStore alloc] initWithManagedObjectContext:context];
client.syncContext = [[MSSyncContext alloc] initWithDelegate:syncDelegate dataSource:store callback:nil];
// Add a Mobile Service filter to enable the busy indicator
self.client = [client clientWithFilter:self];
// Create an MSSyncTable instance to allow us to work with the Athlete table
self.syncAthleteTable = [self.client syncTableWithName:@"Athlete"];
Here's how I add a record for the moment:
NSDictionary *newItem = @{@"firstname": firstname, @"lastname": lastname, @"laterality" : laterality};
[self.athletesService addItem:newItem completion:^{
NSLog(@"New athlete added");
}];
-(void)addItem:(NSDictionary *)item completion:(CompletionBlock)completion
{
// Insert the item into the Athlete table
[self.syncAthleteTable insert:item completion:^(NSDictionary *result, NSError *error)
{
[self logErrorIfNotNil:error];
// Let the caller know that we finished
dispatch_async(dispatch_get_main_queue(), ^{
completion();
});
}];
}
The add works as expected and it is added in a UITableView as I have an NSFetchedResultsController listening on my Main Context.
Here's where the problem occurs. When I synchronize data with the server using this function:
-(void)syncData:(CompletionBlock)completion
{
// push all changes in the sync context, then pull new data
[self.client.syncContext pushWithCompletion:^(NSError *error) {
[self logErrorIfNotNil:error];
[self pullData:completion];
}];
}
-(void)pullData:(CompletionBlock)completion
{
MSQuery *query = [self.syncAthleteTable query];
// Pulls data from the remote server into the local table.
// We're pulling all items and filtering in the view
// query ID is used for incremental sync
[self.syncAthleteTable pullWithQuery:query queryId:@"allAthletes" completion:^(NSError *error) {
[self logErrorIfNotNil:error];
[self refreshDataOnSuccess:completion];
}];
}
- (void) refreshDataOnSuccess:(CompletionBlock)completion
{
MSQuery *query = [self.syncAthleteTable query];
[query readWithCompletion:^(MSQueryResult *results, NSError *error) {
[self logErrorIfNotNil:error];
NSLog(@"Data that pulled from local store: ");
for ( NSDictionary *dict in results.items ) {
NSLog(@"%@ %@", [dict objectForKey:@"firstname"], [dict objectForKey:@"lastname"] );
}
// Let the caller know that we finished
dispatch_async(dispatch_get_main_queue(), ^{
completion();
});
}];
}
After the synchronization the NSFetchedResultsChangeInsert is called a second time for the same record with a slightly different objectID. Here's an example of the first and second objectIDs:
tD7ADE77E-0ED0-4055-BAF6-B6CF8A6960AE9
tD7ADE77E-0ED0-4055-BAF6-B6CF8A6960AE11
I am stuck here.
Any help is highly appreciated. Thank you!