【问题标题】:Migrating a Core Data Store from iCloud to local将核心数据存储从 iCloud 迁移到本地
【发布时间】:2012-09-27 02:07:54
【问题描述】:

我目前正在为 Core Data iCloud 迁移而苦苦挣扎。

我想将商店从 iCloud 通用容器 (.nosync) 移动到本地 URL。问题是,每当我这样称呼时:

[self.persistentStoreCoordinator migratePersistentStore: currentiCloudStore 
                                                  toURL: localURL 
                                                options: nil 
                                               withType: NSSQLiteStoreType 
                                                  error: &error];

我收到此错误:

-[NSPersistentStoreCoordinator addPersistentStoreWithType:configuration:URL:options:error:](1055): CoreData: Ubiquity:  Error: A persistent store which has been previously added to a coordinator using the iCloud integration options must always be added to the coordinator with the options present in the options dictionary. If you wish to use the store without iCloud, migrate the data from the iCloud store file to a new store file in local storage. file://localhost/Users/sch/Library/Containers/bla/Data/Documents/tmp.sqlite. This will be a fatal error in a future release

有人见过这个吗?也许我只是缺少正确的迁移选项?

【问题讨论】:

  • 这是一个 UIManagedDoc 还是一个独立的数据库? UIManagedDoc 在包的根目录有一个 plist。
  • 没有 UIManagedDoc。这是一个“鞋盒”核心数据设置。
  • 忘了提到我在 mac 应用程序 (10.8.2) 中遇到此错误。尚未在 iOS 上尝试过。
  • 啊。我知道了 。尝试直接复制文件而不是托管迁移。然后,您可以使用该文件重新启动新的 PSC。
  • 我收到了同样的信息。我有两个版本的应用程序也使用“鞋盒”模型。一个版本有 iCloud,一个没有。我已经能够毫无问题地在应用程序之间复制数据库。现在有了 iOS 6,我也收到了消息。我很想听到任何解决方案。

标签: objective-c cocoa core-data migration icloud


【解决方案1】:

我的猜测是,根据错误消息,通过将您的选项设置为 nil,PSC 无法移动商店。您可能需要获取原始商店的选项字典并将其传递,而不是将它们设置为 nil。

【讨论】:

    【解决方案2】:

    是的,我也有这个问题。

    我想将 iCloud 商店变成本地商店。


    解决方案 1:将 managedObjects 一个一个移动到 localStore。

    但如果你有一个大数据库,它会很慢。

    所以我昨天找到了第二个解决方案。


    解决方案 2:编辑 iCloud 商店的元数据,

    并将其保存到新位置。

    删除元数据中的“com.apple.coredata.ubiquity.*”键后, 您将获得一家完全本地化的商店。


    这是我的解决方案 2 的代码:

    已经设置了一些属性:

    @property (nonatomic, strong) NSPersistentStoreCoordinator *coordinator;
    @property (nonatomic, strong) NSManagedObjectContext *context;
    
    @property (nonatomic, strong) NSPersistentStore *iCloudStore;
    //represent the iCloud store already using 
    //(after [coordinator addPersistentStore] you get this NSPersistentStore)
    
    @property (nonatomic, strong) NSURL *iCloudStoreURL;
    //represent the iCloud store real location
    //(it is the URL you send to the [coordinator addPersistentStore])
    
    @property (nonatomic, strong) NSURL *iCloudStoreLocalVersionURL;
    //represent the location of local version store you want to save
    

    以及迁移方法:

    -(void)migrateCloudStoreToLocalVersion
    {
        if(!self.iCloudStore)
            return;
    
        // remove previous local version
        [FILE_MANAGER removeItemAtURL:self.iCloudStoreLocalVersionURL
                                error:nil];
    
        // made a copy from original location to the new location
        [FILE_MANAGER copyItemAtURL:self.iCloudStoreURL
                              toURL:self.iCloudStoreLocalVersionURL
                              error:nil];
    
        //prepare meta data
        NSDictionary *iCloudMetadata = [self.coordinator metadataForPersistentStore:self.iCloudStore].copy;
    
        NSMutableDictionary *localVersionMetadata = iCloudMetadata.mutableCopy;
        for(NSString * key in iCloudMetadata){
            if([key hasPrefix:@"com.apple.coredata.ubiquity"]){
                [localVersionMetadata removeObjectForKey:key];
            }
        }
    
        //modify iCloud store
        [self.coordinator setMetadata:localVersionMetadata forPersistentStore:self.iCloudStore];
        [self.coordinator setURL:self.iCloudStoreLocalVersionURL forPersistentStore:self.iCloudStore];
    
        //save to the localVersion location
        [self.context save:nil];
    
        //restore iCloud store
        [self.coordinator setMetadata:iCloudMetadata forPersistentStore:self.iCloudStore];
        [self.coordinator setURL:self.iCloudStoreURL forPersistentStore:self.iCloudStore];
    }
    

    然后你可以使用iCloudStoreLocalVersionURL来使用本地版本存储。

    您可以将此本地版本存储用作本地存储,而不会出现任何错误。

    注意:

    注意元数据中的NSStoreUUIDKey

    您可以选择将其替换为新商店。

    致麦克:

    问题是:

    如果我们在添加 iCloud 商店时使用完整的 iCloud 选项,我们将一切正常,但它仍然是 iCloud 商店。 我们这里想把一个 iCloud 商店变成本地商店。

    如果我们添加除 iCloud 选项之外的一些选项,我们会收到错误消息,并且无法将任何更改保存到此商店。

    所以你的答案不是针对这个问题的。

    【讨论】:

    • 听起来不错!几个月前我实施了第一个解决方案。我会尽快玩第二个。感谢您的示例代码。
    • 感谢您的回答!我应该什么时候调用迁移方法?因为如果用户删除应用并重新安装,iCloud 需要时间从云端检索数据
    【解决方案3】:

    这对我来说很好。如果用户选择另存为菜单选项,我正在使用 NSPersistentDocument 并调用此方法。还值得注意的是,我在文件上设置了自己的元数据,以便知道它是否通过 iCloud 同步。您必须知道,以便在实际打开商店之前设置 pac 时传递正确的选项。我不相信有任何 API 可以以任何其他方式执行此操作。

    // File is NEVER iCloud enabled when we do this.
    - (bool)buildNewStoreAtURL:(NSURL*)newURL type:(NSString *)typeName error:(NSError **)error {
    
        //FLOG(@"buildNewStoreAtURL:type: called");
    
        NSError *myError;
    
        // We only have one store
        NSPersistentStore *currentStore = [self.managedObjectContext.persistentStoreCoordinator.persistentStores objectAtIndex:0];
        NSDictionary *currentOptions = currentStore.options;
    
        // We need to create new options for the new document if it is currently synced via iCloud.
        NSMutableDictionary *newOptions = [[NSMutableDictionary alloc] initWithDictionary:currentOptions];
        [newOptions setObject:@"DELETE" forKey:@"JOURNAL"];
    
        // Remove any iCloud options
        [newOptions removeObjectForKey:NSPersistentStoreUbiquitousContentNameKey];
    
        // Instruct to remove any Core Data iCloud metadata
        [newOptions setObject:[NSNumber numberWithBool:YES] forKey:NSPersistentStoreRemoveUbiquitousMetadataOption];
    
    
        NSPersistentStoreCoordinator *psc = self.managedObjectContext.persistentStoreCoordinator;
    
        //FLOG(@"   create a new store at the required URL");
        NSPersistentStore *newStore = [psc migratePersistentStore:currentStore toURL:newURL options:newOptions withType:typeName error:&myError];
    
        if (newStore) {
            //FLOG(@"   store seems OK");
            // Set our own metadata flags so we can tell of the file is synced via iCloud
            // before we open the store (we have to pass in the right ubiquity name if it is)
            NSDictionary *dict = [self getiCloudMetaDataForStore:[psc metadataForPersistentStore:newStore] iCloud:NO ubiquityName:nil];
            [psc setMetadata:dict forPersistentStore:newStore];
            return YES;
        }
        else {
    
            FLOG(@" problem creating new document");
            FLOG(@"  - error is %@, %@", myError, myError.userInfo);
            *error = myError;
            return NO;
        }
    
    }
    

    【讨论】:

      【解决方案4】:

      从 iOS 7 开始,有一种更简单、更合乎逻辑的方式来迁移商店,同时放弃 iCloud 无处不在,只需传递 NSPersistentStoreRemoveUbiquitousMetadataOption 选项:

      NSDictionary *options = [NSDictionary dictionaryWithObject:@YES
                                                          forKey:NSPersistentStoreRemoveUbiquitousMetadataOption];
      [self.persistentStoreCoordinator migratePersistentStore: currentiCloudStore 
                                                    toURL: localURL 
                                                  options: nil 
                                                 withType: NSSQLiteStoreType 
                                                    error: &error];
      

      这会将商店迁移到本地 URL,并删除所有 iCloud 元数据,基本上是 @frogcjn 手动执行的操作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-10-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-11
        • 2015-11-10
        • 2017-07-11
        • 2014-01-29
        相关资源
        最近更新 更多