9

我目前正在为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

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

4

4 回答 4

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 选项之外的一些选项,我们将收到错误消息并且无法将任何更改保存到此商店。

所以你的答案不适用于这个问题。

于 2012-12-27T05:56:53.043 回答
2

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

于 2012-11-24T21:00:44.360 回答
1

这对我来说很好。如果用户选择另存为菜单选项,我正在使用 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;
    }

}
于 2013-11-06T00:07:13.013 回答
1

从 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 手动执行的操作。

于 2016-01-05T20:40:15.057 回答