在我的应用程序上启用 iCloud 时,现有核心数据数据库未上传到 iCloud

Posted

技术标签:

【中文标题】在我的应用程序上启用 iCloud 时,现有核心数据数据库未上传到 iCloud【英文标题】:Existing Core Data Database Not Uploading to iCloud When Enabling iCloud On My App 【发布时间】:2014-05-11 13:43:08 【问题描述】:

我在 App Store 中有一个简单的应用程序,它是一个 UITableView,由用户在模态调用的视图中填写一些 UITextFields 填充。用户按下保存,所有内容都保存到 Core Data 并使用NSFetchedResultsControllersUITableView 被更新。

我现在正在更新我的应用程序以引入 iCloud 同步(和 iPad 版本)。

我是iCloud 开发的新手,虽然我关注http://goddess-gate.com/dc2/index.php/post/452 的帖子已经有几年了,但它主要对我有用。

问题

在不进一步讨论其他问题的情况下,我现在遇到的一个问题是,如果我使用一些数据(未启用 iCloud)运行我的应用程序的 App Store 版本,当我使用我在 Xcode 中的开发版本更新我的应用程序,我希望我的原始数据仍然存在并因此上传到 iCloud。

我的应用中没有显示不要上传的复选框,但我会解决的。现在,问题是当我更新我的应用程序时,我从一个完全空白的数据库开始,尽管我怀疑这只是我的代码现在实际显示数据的问题,因为在我的设备设置中,它显示了 9.7 KB 的数据存储在 iCloud 中(在进行此测试之前,我确保删除了 iCloud 备份数据)。

我在 Developer Portal 中调整了我的 App Id 以包含 iCloud,并调整了 Xcode 以包含它,同时在 Developer 中创建新的 SSL 证书并将新的配置文件重要到 Xcode 中。

更新:对我的应用进行了大量更改并删除了旧代码

这是我的App DelegatepersistentStoreCoordinator 代码:(遵循汤姆回答的建议)

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator

    if (_persistentStoreCoordinator != nil) 
        return _persistentStoreCoordinator;
    

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Planner.sqlite"];
    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    NSDictionary *options = @
                              NSMigratePersistentStoresAutomaticallyOption : @YES,
                              NSInferMappingModelAutomaticallyOption : @YES
                              ;
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) 

        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    

    NSPersistentStore *ps = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error];

    NSFileManager *fm = [NSFileManager defaultManager];
    NSURL *url = [fm URLForUbiquityContainerIdentifier:nil];
    NSDictionary *iCloudOptions = @
                              NSMigratePersistentStoresAutomaticallyOption : @YES,
                              NSInferMappingModelAutomaticallyOption : @YES,
                              NSPersistentStoreUbiquitousContentNameKey : @"EnvysStore"
                              ;
    NSPersistentStore *store = [[_persistentStoreCoordinator persistentStores] firstObject];

    store = [_persistentStoreCoordinator migratePersistentStore:ps toURL:url options:iCloudOptions withType:NSSQLiteStoreType error:&error];

    return _persistentStoreCoordinator;

但是,在运行我的应用程序时,应用程序崩溃:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'nil is not a valid persistent store' on the 

    store = [_persistentStoreCoordinator migratePersistentStore:ps toURL:url options:iCloudOptions withType:NSSQLiteStoreType error:&error];

问题

所以问题是,当我的应用程序的应用商店版本包含一些数据然后更新到这个版本时,首先应用程序崩溃如上所述,但是一旦我得到修复,我希望我现有的数据被迁移到云端。

对此的任何指导将不胜感激!

【问题讨论】:

iCloud 核心数据在 ios7 中发生了很多的变化。任何比这更旧的指南都是过时的,不应遵循。此外,Apple 自己建议您不要尝试混合运行 iOS 7 和更早版本的支持 iCloud 的应用程序。查找 ios7 指南并遵循该指南。 Objc.io 前段时间有一个不错的。 亲爱的@jrturton - 非常感谢您的回复。好消息是我在我的应用程序中只使用了 iOS 7,而不是在其他版本之间工作,我从你几分钟前谈论的网站上找到了一篇文章:obj.io/issue-10/icloud-core-data.html。不幸的是,对于新手来说,虽然它包含代码,但它并没有准确说明需要插入的位置。我是否应该创建一个引用该文章的新问题? 【参考方案1】:

在不进一步讨论其他问题的情况下,我现在遇到的一个问题是,如果我使用一些数据(未启用 iCloud)运行我的应用程序的 App Store 版本,当我使用我在 Xcode 中的开发版本更新我的应用程序,我希望我的原始数据仍然存在并因此上传到 iCloud。

事情没那么简单。 Core Data 的 iCloud 集成使用事务日志来同步更改。每次将更改保存到持久存储文件时,都会生成事务日志。如果您只是在现有数据存在时添加 iCloud 支持,则不会为该数据生成任何事务。没有事务日志,没有同步,并且您的数据保持在本地。

要将现有数据移动到 iCloud,您需要将持久存储迁移到新文件,在此过程中为所有现有数据生成事务。最简单的方法是调用[NSPersistentStoreCoordinator migratePersistentStore:toURL:options:withType:error:],它采用与添加持久存储文件时相同的选项。将您的本地商店迁移到支持 iCloud 的新商店,如果一切正常,您将获得交易日志并上传数据。

如果您的持久性存储非常大,您可能需要使用自定义迁移代码。但大多数时候,内置的迁移方法就可以了。

【讨论】:

亲爱的汤姆 - 非常感谢你,这是有道理的。仅 iOS 7 的应用程序是否也是这种情况,现有的本地数据基本上需要首先迁移到云端?如果是这样,这是有道理的,我唯一不确定的是用于 migratePersistentStore 的参数 - 它想要将 NSPersistentStore 作为参数 - 我应该创建一个实例并将其设置为 nil 在调用它之前? 我想我需要创建类似的东西: NSPersistentStore *store = [[_persistentStoreCoordinator persistentStores] firstObject];在persistentStore中,但是当我运行代码migratePersistent时,它会因“nil is not a valid persistent store”而崩溃。 这就是您需要做的,但在此之前您需要使用旧的非 iCloud 选项添加持久存储,以便有一个 NSPersistentStore 进行迁移。所以 (a) 添加没有 iCloud 的商店,然后 (b) 迁移到 iCloud。 感谢汤姆,对于这么多问题,我感到非常抱歉。您的答案当然是公认的。考虑到你所说的,我继续更新问题以反映我的代码以及我认为的方法。但是我遇到了崩溃。这对我来说都是全新的,所以迁移方面似乎我已经接近了......但还没有完全到那里! 代码中的问题是您要添加相同的持久存储两次。第二次是错误,所以它失败了,但你没有检查错误状态,所以你没有注意到。您应该放弃对addPersistentStore:etc: 的第二次冗余调用。

以上是关于在我的应用程序上启用 iCloud 时,现有核心数据数据库未上传到 iCloud的主要内容,如果未能解决你的问题,请参考以下文章

iOS:将现有核心数据数据库迁移到 iCloud

将核心数据与 iCloud 同步 - 不包括实体

在我的应用程序中使用配置文件启用 iCloud

如何将现有核心数据 iOS 7 应用程序的数据迁移到 iCloud?

核心数据 - iCloud 行为

仅为 OS X 10.8.x 和 iOS 6.x 在 iCloud 中启用核心数据同步