ios – 将iCloud存储迁移到本地存储,并通过每个应用程序启动确保数据存在

基于这里的问题:
Migrate iCloud data to Local store and stopping iCloud from still responding关于将iCloud存储移动到本地存储并确保禁用iCloud通知,我有下一个我坚持的方案.

问题

现在,当用户在第一台设备上运行应用程序时,他们会在一开始就询问是否要启用iCloud.如果选择是,则将数据迁移到iCloud.如果用户在第二个设备中连接,则会询问他们是否要在开始时使用iCloud,如果他们选择“是”,则会同步来自第一个设备的数据.

如果第二个设备上的用户决定不再使用iCloud,他们可以在应用程序中导航并关闭该设备的iCloud.这在后端将其数据从iCloud存储迁移到本地存储.从用户的角度来看,他们的所有数据都存在(无论是存储在云中还是本地存储对用户来说都无关紧要).

问题是当我迁移数据时,它成功迁移到本地iCloud存储并成功停止侦听iCloud通知.那个方面有效,这是我之前提出的堆栈溢出问题(Migrate iCloud data to Local store and stopping iCloud from still responding).

具体问题是,当用户重新启动应用程序时,该应用程序现在为空,没有数据.这当然不是预期的效果.

为了完整起见,“迁移代码”基于另一个堆栈溢出问题,但为了方便起见,我将其粘贴在此处:

- (void)migrateiCloudStoreToLocalStore {

NSLog(@"Migrate iCloudToLocalStore");
NSPersistentStore *store = self.persistentStoreCoordinator.persistentStores.lastObject;

//NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Envylope.sqlite"];
NSURL *storeURL = [self.persistentStoreCoordinator.persistentStores.lastObject URL];
NSLog(@"Current Store URL (before iCloud to Local migration): %@", [storeURL description]);

NSDictionary *localStoreOptions = nil;
localStoreOptions = @{ NSPersistentStoreRemoveUbiquitousMetadataOption : @YES,
                       NSMigratePersistentStoresAutomaticallyOption : @YES,
                       NSInferMappingModelAutomaticallyOption : @YES};

NSPersistentStore *newStore = [self.persistentStoreCoordinator migratePersistentStore:store
                                                                                 toURL:storeURL
                                                                               options:localStoreOptions
                                                                              withType:NSSQLiteStoreType error:nil];

[self reloadStore:newStore];
}

- (void)reloadStore:(NSPersistentStore *)store {
NSLog(@"Reload Store");        
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Envylope.sqlite"];
NSDictionary *localStoreOptions = nil;
localStoreOptions = @{ NSPersistentStoreRemoveUbiquitousMetadataOption : @YES,
                       NSMigratePersistentStoresAutomaticallyOption : @YES,
                       NSInferMappingModelAutomaticallyOption : @YES};

if (store) {
    [self.persistentStoreCoordinator removePersistentStore:store error:nil];
}

[self.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                              configuration:nil
                                                        URL:storeURL
                                                    options:localStoreOptions
                                                      error:nil];
storeURL = [self.persistentStoreCoordinator.persistentStores.lastObject URL];
NSLog(@"Current Store URL (after iCloud to Local migration): %@", [storeURL description]);

NSLog(@"Done reloading");

[[NSUserDefaults standardUserDefaults]setBool:YES forKey:@"MigratedFromiCloudToLocal"];
[[NSUserDefaults standardUserDefaults]synchronize];

所有的魔法都发生在persistentStoreCoordinator中……它很乱,但是我需要让这部分工作然后可以清理它:

    - (NSPersistentStoreCoordinator *)persistentStoreCoordinator
    {
        if (_persistentStoreCoordinator != nil) {
            return _persistentStoreCoordinator;
        }

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Envylope.sqlite"];

    NSError *error = nil;

    NSURL *iCloud = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier: nil];
    NSDictionary *options = nil;

    if ((iCloud) && (![[NSUserDefaults standardUserDefaults] boolForKey:@"iCloudOn"]) && (![[NSUserDefaults standardUserDefaults]boolForKey:@"OnLatestVersion"]))
    {
        NSLog(@"In the persistent store, iCloud is enabled in the app device but not yet in the app and not on the latest version");

        options = @{                                       NSMigratePersistentStoresAutomaticallyOption : @YES,
                                                           NSInferMappingModelAutomaticallyOption : @YES};

    }
    else if ((iCloud) && ([[NSUserDefaults standardUserDefaults] boolForKey:@"iCloudOn"]) && ([[NSUserDefaults standardUserDefaults]boolForKey:@"OnLatestVersion"]))
    {
        NSLog(@"In the persistent store, iCloud is enabled, we're using iCloud from the Tutorial and we're on the latest version");
        NSURL *cloudURL = [self grabCloudPath:@"iCloud"];
        options = @{                                       NSMigratePersistentStoresAutomaticallyOption : @YES,
                                                           NSInferMappingModelAutomaticallyOption : @YES,
                                                           NSPersistentStoreUbiquitousContentURLKey: cloudURL, NSPersistentStoreUbiquitousContentNameKey: @"EnvyCloud"};


    }
    else if ((iCloud) && (![[NSUserDefaults standardUserDefaults] boolForKey:@"iCloudOn"]) && ([[NSUserDefaults standardUserDefaults]boolForKey:@"OnLatestVersion"]))
    {
        NSLog(@"In the persistent store, iCloud is enabled, we're on the latest version, btu we're not using icloud in the App");

        options = @{                                       NSMigratePersistentStoresAutomaticallyOption : @YES,
                                                           NSInferMappingModelAutomaticallyOption : @YES};

    }
    else
    {
        NSLog(@"iCloud is just not enabled");

        options = @{                                       NSMigratePersistentStoresAutomaticallyOption : @YES,
                                                           NSInferMappingModelAutomaticallyOption : @YES};

    }

    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {

        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        //abort();
    }
    return _persistentStoreCoordinator;
}

因此,在用户在应用程序中启用iCloud然后决定不再在此特定设备上安装iCloud的情况下,iCloud通知将被删除,商店将从iCloud Store迁移到本地存储并设置NSUserDefaults.在下一次启动应用程序时…第3条if语句在persistentStoreCoordinator中评估为true,正确地说我们在最新版本上,iCloud已启用(在设备中)但未在应用程序中启用,但随后显示应用程序绝对没有任何条目,有点像开始新鲜.

我如何克服这一点并返回刚刚迁移的商店?

任何想法都会非常感激.

最佳答案 应用程序启动时没有数据指向持久性存储协调器.

看起来对选项字典的评估很好,但在任何一种结果中,您总是使用相同的持久性存储URL设置协调器.

同样,在迁移例程中,您将迁移持久性存储对象,但使用相同的URL.这不起作用,因为那是保存实际文件的地方.您需要本地存储和iCloud存储的不同URL,然后您可以正确地迁移数据并选择删除不再需要的URL(从协调器中删除存储后).

使用相应的URL设置协调器,具体取决于您的评估结果 – 并且希望 – 您应该在应用启动时看到您的数据.

点赞