How can I migrate the data from the iCloud store f

2019-02-15 23:31发布

问题:

I have iCloud in my app. I've removed iCloud from my app, but on ios 6 app crashes and I get this message:

  -[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.

How can I solve this error? How can I migrate the data from the iCloud store file to a new store file in local storage?

回答1:

YES, I have this question too. I want to turn a iCloud store to a local store


Solution 1 :Moving managedObjects one-by-one to the localStore.

But if you have a large database, it will be so slow.

So I found a second solution yesterday.


Solution 2: Editing the metadata of the iCloud store,

and saving it to the new location.

After you remove "com.apple.coredata.ubiquity.*" keys in metadata, you'll get a fully local store.


Here is my code for solution 2:

There are some properties already set:

@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

And the migrate method:

-(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];
}

Then you can use the iCloudStoreLocalVersionURL to using the local version store.

You can use this local version store as local store, without any error.

Note:

Notice the NSStoreUUIDKey in the metadata,

you can optional replace it for the new store.



回答2:

I believe you have to change out the UUID number too, I would get errors on the next run of the app that it was loading the same store twice. so i made this modification

    if (!self.iCloudStore) return;
NSError *error = nil;

NSURL* localStoreURL = [self fallbackStoreURL];

 NSFileManager *fm = [[NSFileManager alloc] init];

 if (!self.fallbackStore) [self loadFallbackStore:&error];

NSString* fallBackUUID;

//find UUID of original to put back in later
NSDictionary *fallBackMetadata = [_psc metadataForPersistentStore:self.fallbackStore].copy;
for(NSString* key in fallBackMetadata)
{
    if([key hasPrefix:@"NSStoreUUID"])
    {
        fallBackUUID = [fallBackMetadata objectForKey:key];
        break;
    }
}

[fm removeItemAtURL:localStoreURL error:nil];


//prepare meta data
NSDictionary *iCloudMetadata = [_psc metadataForPersistentStore:self.iCloudStore].copy;
NSMutableDictionary *localVersionMetadata = iCloudMetadata.mutableCopy;
for(NSString* key in iCloudMetadata)
{
    if([key hasPrefix:@"com.apple.coredata.ubiquity"])
    {
        [localVersionMetadata removeObjectForKey:key];
    }

    if([key hasPrefix:@"NSStoreUUID"])
    {
         if (fallBackUUID) [localVersionMetadata setObject:fallBackUUID forKey:key];
    }
}


//modify iCloud store
[_psc setMetadata:localVersionMetadata forPersistentStore:self.iCloudStore];
[_psc setURL:localStoreURL forPersistentStore:self.iCloudStore];

// make a copy from original location to the new location
[fm copyItemAtURL:[self iCloudStoreURL]
                      toURL:localStoreURL
                      error:nil];

 [_fallbackContext save:nil];


[_psc setMetadata:iCloudMetadata forPersistentStore:self.iCloudStore];
[_psc setURL:[self iCloudStoreURL] forPersistentStore:self.iCloudStore];