阅读背景:

iCloud不能正确同步核心数据(iOS7)

来源:互联网 

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:

我正在尝试使用iCloud在设备之间同步核心数据(使用新的iOS7方法)。在使用模拟器进行测试时,我仍然看到同步的问题。有时,来自一个模拟器的数据不会同步到另一个模拟器。有什么问题吗?下面是来自appdelegate的大部分代码。

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?

有什么不对劲吗?

1 个解决方案

#1


4  

Here is how I do it. It might be an easy way to simplify and unclutter your code.

我是这样做的。这可能是一种简化和整理代码的简单方法。

self.managedObjectContext = [[NSManagedObjectContext alloc] 
                            initWithConcurrencyType:NSMainQueueConcurrencyType];
self.managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
self.managedObjectContext.persistentStoreCoordinator = 
                            [[NSPersistentStoreCoordinator alloc] 
                            initWithManagedObjectModel:self.managedObjectModel];

[self.managedObjectContext.persistentStoreCoordinator 
    addPersistentStoreWithType:NSSQLiteStoreType
    configuration:nil
    URL:self.storeURL
    options:@{ NSPersistentStoreUbiquitousContentNameKey : @"iCloudStore" }
    error:&error];

The only iCloud bit is the options parameter. (I removed other options for clarity.) The store URL is just [documentsDirectory URLByAppendingPathComponent:@"Store.sqlite"].

唯一的iCloud位是选项参数。(为了清晰起见,我删除了其他选项。)store URL只是[documentsDirectory URLByAppendingPathComponent:@"Store.sqlite"]。

I am also listening to these:

我也在听这些:

NSPersistentStoreDidImportUbiquitousContentChangesNotification
NSPersistentStoreCoordinatorStoresWillChangeNotification
NSPersistentStoreCoordinatorStoresDidChangeNotification

In the first one, I call

在第一个,我打电话。

[self.managedObjectContext mergeChangesFromContextDidSaveNotification:note];

and post another notification to update the UI; in the second one, I save; in the third one I also update the UI.

并发布另一个通知更新UI;在第二个,我保存;在第三个版本中,我还更新了UI。

For me that's really all there is to it. It works flawlessly up to now.

对我来说,这就是一切。到目前为止,它运行得完美无缺。

Credit goes to iCloudCoreDataStack.

信贷iCloudCoreDataStack。


分享到: