I'm attempting to sync Core Data among devices using iCloud (using the new iOS7 method). I'm still seeing issues with the syncing when testing with the simulators. Sometimes data from one simulator won't sync to another simulator. What could ever be the problem? Here's most of the code from the AppDelegate.m:
NSManagedObjectContext *context = [self managedObjectContext];
if (!context)
[self displayAlert];
rvc.managedObjectContext = context;
The main code:
#pragma mark -
#pragma mark Core Data stack
/**
Returns the managed object context for the application.
If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
*/
- (NSManagedObjectContext *)managedObjectContext {
if (__managedObjectContext != nil) {
return __managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
NSManagedObjectContext* moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[moc performBlockAndWait:^{
[moc setPersistentStoreCoordinator: coordinator];
if(!isOldVersion){
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(mergeChangesFrom_iCloud:) name:NSPersistentStoreDidImportUbiquitousContentChangesNotification object:coordinator];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(storesWillChange:) name:NSPersistentStoreCoordinatorStoresWillChangeNotification object:coordinator];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(storesDidChange:) name:NSPersistentStoreCoordinatorStoresDidChangeNotification object:coordinator];
[moc setMergePolicy:[[NSMergePolicy alloc] initWithMergeType:NSMergeByPropertyObjectTrumpMergePolicy]];
}
}];
__managedObjectContext = moc;
}
return __managedObjectContext;
}
- (void)storesWillChange:(NSNotification *)notification {
if (__managedObjectContext) {
[__managedObjectContext performBlockAndWait:^{
if ([__managedObjectContext hasChanges]) {
NSError *error = nil;
[__managedObjectContext save:&error];
}
[__managedObjectContext reset];
}];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:@"SCEmptyClips" object:self userInfo:nil];
});
}
}
-(void)storesDidChange:(NSNotification *)n{
[[NSNotificationCenter defaultCenter] postNotificationName:@"SCDataChange" object:nil userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:@"SCPBUpdateCheck"]];
}
/**
Returns the managed object model for the application.
If the model doesn't already exist, it is created by merging all of the models found in the application bundle.
*/
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel != nil) {
return managedObjectModel;
}
managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
return managedObjectModel;
}
/**
Returns the persistent store coordinator for the application.
If the coordinator doesn't already exist, it is created and the application's store added to it.
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (__persistentStoreCoordinator != nil){
return __persistentStoreCoordinator;
}
firstPost = NO;
NSLog(@"STARTING to configure iCloud / new persistent store");
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"SmartCopy.sqlite"]];
NSDictionary *options;
if(!isOldVersion && [[userDefaults valueForKey:@"SCiCloudMode"] boolValue]){
options = @{NSPersistentStoreUbiquitousContentNameKey: @"MYStoreName"};
}else if(!isOldVersion){
options = @{NSPersistentStoreRemoveUbiquitousMetadataOption: @YES};
}else{
options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
}
[__persistentStoreCoordinator lock];
result = [__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:nil];
if (!result)
[self displayAlert];
[__persistentStoreCoordinator unlock];
NSLog(@"Persistent store added. Now **%u** store(s)", [[[self persistentStoreCoordinator] persistentStores] count]);
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:@"SCDataChange" object:nil userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:@"SCPBUpdateCheck"]];
firstPost = YES;
});
return __persistentStoreCoordinator;
}
- (void)mergeChangesFrom_iCloud:(NSNotification *)notification {
NSLog(@"iCloud actual import");
NSLog(@"insert %@", [[notification userInfo] valueForKey:@"inserted"]);
NSLog(@"delete %@", [[notification userInfo] valueForKey:@"deleted"]);
NSLog(@"update %@", [[notification userInfo] valueForKey:@"updated"]);
[__managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
[[NSNotificationCenter defaultCenter] postNotificationName:@"SCDataChange" object:nil userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:@"SCPBUpdateCheck"]];
}
#pragma mark -
#pragma mark Application's documents directory
/**
Returns the path to the application's documents directory.
*/
- (NSString *)applicationDocumentsDirectory {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
Does anything there look wrong?
Here is how I do it. It might be an easy way to simplify and unclutter your code.
The only iCloud bit is the options parameter. (I removed other options for clarity.) The store URL is just
[documentsDirectory URLByAppendingPathComponent:@"Store.sqlite"]
.I am also listening to these:
In the first one, I call
and post another notification to update the UI; in the second one, I save; in the third one I also update the UI.
For me that's really all there is to it. It works flawlessly up to now.
Credit goes to iCloudCoreDataStack.