将Core Data Store从iCloud迁移到本地

时间:2012-10-05 21:35:34

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

我目前正在努力解决 Core Data iCloud迁移问题。

我想将商店从iCloud ubiquity容器(.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 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分: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选项之外的一些选项,我们将收到错误,并且无法保存对此商店的任何更改。

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

答案 2 :(得分: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;
    }

}

答案 3 :(得分:0)

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