iOS 7 iCloud 和(启用/禁用)Core Data - 永无止境的故事

Posted

技术标签:

【中文标题】iOS 7 iCloud 和(启用/禁用)Core Data - 永无止境的故事【英文标题】:iOS 7 iCloud & (enable/disable) Core Data - The never ending story 【发布时间】:2014-03-07 22:52:07 【问题描述】:

目前我尝试使用 CoreData 建立 iCloud。我的应用“仅”基于 ios 7,因此启用 iCloud 非常容易。基础工作非常好(保存到 iCloud)。我现在搜索了两个多星期,但我没有找到解决我的问题的方法。

我的问题: 如果用户在设置中启用/禁用 iCloud 或更改 iCloud 帐户,我的应用程序应该以两种方式合并更改。 所以这是我的场景:

应用启动 -> iCloud 关闭 -> 数据已保存(本地) -> 用户打开 iCloud -> 本地数据将合并到 iCloud

应用启动 -> iCloud 开启 -> 数据已保存 (iCloud) -> 用户关闭 iCloud -> iCloud 数据将合并到本地

在许多其他线程中,一些开发人员写道,只有一个具有相同选项和 url 的持久存储就足够了,因为 iOS 7 核心数据在禁用 iCloud 时处理自动回退存储,如果可用则触发合并再次。但这对我不起作用。

这里有一些代码sn-ps:

- (NSURL*)storeURL
NSURL* documentsDirectory = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:NULL];
return [documentsDirectory URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.sqlite",coreDataFileName]];


- (NSURL*)modelURL
return [[NSBundle mainBundle] URLForResource:coreDataFileName withExtension:@"momd"];


-(NSMutableDictionary*)getICloudPersistentStoreOptions
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:
 NSInferMappingModelAutomaticallyOption];

//if(self.hasICloudAccountOnDevice & self.iCloudLokalIsAvailable)
[options setObject:@"iCloudStore" forKey:NSPersistentStoreUbiquitousContentNameKey];        
//
return options;



- (NSManagedObjectContext *)managedObjectContext
if (masterContext != nil)
    return masterContext;

NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
    masterContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    masterContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
    [masterContext setPersistentStoreCoordinator: coordinator];

return masterContext;


- (NSManagedObjectModel *)managedObjectModel
if (managedObjectModel != nil)
    return managedObjectModel;

managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:self.modelURL];
return managedObjectModel;


- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
if((persistentStoreCoordinator != nil))
    return persistentStoreCoordinator;

[self createPersistentStoreCoordinator];
return persistentStoreCoordinator;


-(void)createPersistentStoreCoordinator
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
NSPersistentStoreCoordinator *psc = persistentStoreCoordinator;

// iCloud notification subscriptions
NSNotificationCenter *dc = [NSNotificationCenter defaultCenter];
[dc addObserver:self
       selector:@selector(storesWillChange:)
           name:NSPersistentStoreCoordinatorStoresWillChangeNotification
         object:psc];

[dc addObserver:self
       selector:@selector(storesDidChange:)
           name:NSPersistentStoreCoordinatorStoresDidChangeNotification
         object:psc];

[dc addObserver:self
       selector:@selector(persistentStoreDidImportUbiquitousContentChanges:)
           name:NSPersistentStoreDidImportUbiquitousContentChangesNotification
         object:psc];

// Set up iCloud persistent store in another thread:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^

    NSError* error;
    [psc lock];
    [psc addPersistentStoreWithType:NSSQLiteStoreType
                      configuration:nil
                                URL:self.storeURL
                            options:[self getICloudPersistentStoreOptions]
                              error:&error];
    [psc unlock];
);

在“storeWillChange”方法中,我想在 NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted 之后实现一些重复数据删除代码,但那是另一回事。

NSPersistentStoreDidImportUbiquitousContentChangesNotification 当前未使用(我认为只有在其他设备也将一些数据保存到 iCloud 时才会调用它 .

每次应用启动时都会调用来自 NSPersistentStoreCoordinatorStoresDidChangeNotification 的“storeDidChange”。所以目前我不知道我应该在那里做什么。

正如我之前写的那样,这对我不起作用,如果我启用或禁用 iCloud,数据将不会被合并。

请帮助我 - 我的想法错了吗??

【问题讨论】:

我看过一个 Duncan 的网站,它很棒,但我的脑子里有些过头了。我正要放弃,发现了这个,github.com/mluisbrown/iCloudCoreDataStack 【参考方案1】:

看看这里,我对这些问题做了一些注释。 http://ossh.com.au/design-and-technology/software-development/sample-library-style-ios-core-data-app-with-icloud-integration/sample-apps-explanations/

还可以查看处理 iCloud 帐户转换的示例应用程序,我认为您可以在需要转换并且目标商店已经存在时选择合并选项。

请注意,如果用户在 iCloud 开启时选择使用本地存储,则会删除 iCloud 存储。也不是说在 iCloud 关闭后没有尝试迁移 iCloud 商店。根据 Apple 的说法,一旦用户退出 iCloud,您就不能依赖 iCloud 商店。

【讨论】:

谢谢!这有很大帮助。它真的很棒!我可以将 OSCDStackManager 的修改版本用于私人和商业用途吗?但无论如何,OSCDStackManager 中存在一些问题。我们可以在这里讨论这个吗? 当然可以使用它,如果您认为需要解决的问题或您对它的工作方式/原因有疑问,请在网站上向我发送消息,我将不胜感激。 @Duncan - 如果您可以在示例代码中添加更多 cmets 等,那就太好了。以它目前的状态,我没有信心,也不知道使用它的好方法......只是我的意见 是的,我知道,我在一周左右的时间内将它一起破解,作为生产应用程序的概念证明,因此它并不是真正的教程。必须写一本书才能涵盖所有方面! @user2075873 我一直没有收到电子邮件,请再次尝试发送至 ducan.groenewald@ossh.com.au。【参考方案2】:

有两种方法可以做到这一点:

    将实体从一个商店深度复制到另一个商店; 将商店从本地迁移到 iCloud,反之亦然。

由于代码较少,第二种方式更容易。

【讨论】:

以上是关于iOS 7 iCloud 和(启用/禁用)Core Data - 永无止境的故事的主要内容,如果未能解决你的问题,请参考以下文章

在 iOS 7 中禁用 Core Data 中的 iCloud(也就是将持久存储文件迁移到本地)

iCloud Core Data iOS 6 到 iOS 7 最初是空的本地后备存储

iCloud Core 数据同步设置

如何在 iOS 7 App 中禁用 iCloud

启用和禁用 iCloud 时的 XCTest

iOS 7 中的 iCloud、Core Data 和来自 Web 服务的数据