【问题标题】:iCloud not syncing properly for Core Data (iOS7)iCloud 无法正确同步 Core Data (iOS7)
【发布时间】:2013-12-28 12:28:21
【问题描述】:

我正在尝试使用 iCloud(使用新的 iOS7 方法)在设备之间同步 Core Data。在使用模拟器进行测试时,我仍然看到同步问题。有时来自一个模拟器的数据不会同步到另一个模拟器。可能是什么问题?以下是 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;
}

有什么地方看起来不对吗?

【问题讨论】:

    标签: iphone ipad core-data ios7 icloud


    【解决方案1】:

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

    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 参数。 (为了清楚起见,我删除了其他选项。)商店 URL 只是 [documentsDirectory URLByAppendingPathComponent:@"Store.sqlite"]。

    我也在听这些:

    NSPersistentStoreDidImportUbiquitousContentChangesNotification
    NSPersistentStoreCoordinatorStoresWillChangeNotification
    NSPersistentStoreCoordinatorStoresDidChangeNotification
    

    在第一个,我叫

    [self.managedObjectContext mergeChangesFromContextDidSaveNotification:note];
    

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

    对我来说,这就是它的全部。到目前为止它完美无缺。

    归功于iCloudCoreDataStack。

    【讨论】:

    • 谢谢,我喜欢那个 GitHub 项目。将核心数据堆栈保留在一个单独的类中的想法很棒。同步现在似乎更好,但似乎仍然存在一些模拟器同步问题。在日志显示“...使用本地存储:0”之前向 Core Data 添加新数据是否有问题?
    • 根据我的测试,NSPersistentStoreDidImportUbiquitousContentChangesNotification 从未被调用过。但是,我从来没有同时运行两个设备。我已经看到我在一个模拟器中添加了一个条目,但它没有出现在第二个模拟器上。是否应该调用该通知来导入新条目,而不是?
    • 不,它应该在您的应用程序的第二个实例启动并且有更改时触发。不确定您的第一个问题。
    • @Hope4You 如果您有一个活跃的 iCloud 存储,那么最好等到 Core Data 切换到使用该存储。如果您有需要满足的数据关系,则尤其如此。我为此苦苦挣扎了一段时间,现在似乎运行稳定了。看看这个链接,特别是有关启用用户界面的相关页面,到目前为止,该方法已被证明非常可靠。 ossh.com.au/design-and-technology/software-development/…
    • @DuncanGroenewald 您是否有任何示例代码说明如何检测 Core Data 切换到 iCloud 商店后的情况?
    猜你喜欢
    • 1970-01-01
    • 2014-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-26
    • 1970-01-01
    • 2014-06-02
    • 2017-03-07
    相关资源
    最近更新 更多