iCloud未正确同步Core Data(iOS7)

时间:2013-12-10 19:45:15

标签: iphone ipad core-data ios7 icloud

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

NSManagedObjectContext *context = [self managedObjectContext];
if (!context)
    [self displayAlert];
rvc.managedObjectContext = context;

主要代码:

#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;
}

有什么问题吗?

1 个答案:

答案 0 :(得分:4)

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

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];

唯一的iCloud位是options参数。 (为清楚起见,我删除了其他选项。)商店网址只有[documentsDirectory URLByAppendingPathComponent:@"Store.sqlite"]

我也在听这些:

NSPersistentStoreDidImportUbiquitousContentChangesNotification
NSPersistentStoreCoordinatorStoresWillChangeNotification
NSPersistentStoreCoordinatorStoresDidChangeNotification

在第一个中,我打电话给

[self.managedObjectContext mergeChangesFromContextDidSaveNotification:note];

并发布另一个通知来更新UI;在第二个,我救;在第三个我也更新了UI。

对我来说,真的就是它。它到目前为止完美无瑕。

信用转到iCloudCoreDataStack