将iCloud Store迁移到本地存储,并确保每个应用程序启动时都有数据 [英] Migrating an iCloud Store to a Local Store and making sure the data is there through each app launch

查看:206
本文介绍了将iCloud Store迁移到本地存储,并确保每个应用程序启动时都有数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据这里的问题:将iCloud数据迁移到本地存储并停止iCloud仍然响应将iCloud存储移动到本地存储并确保iCloud通知已禁用,我有下一个方案我坚持。



发布



目前,当用户在第一个设备,他们在开始时被要求是否要启用iCloud。如果选择是,则数据将迁移到iCloud。如果用户在第二个设备中连接,会询问他们是否要在开始时使用iCloud,如果他们选择是,则第一个设备的数据将同步。



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



问题是当我迁移数据时,它成功迁移到本地iCloud存储,并成功停止侦听iCloud通知。这个方面工作,这是在堆栈溢出问题,我以前问(将iCloud数据迁移到本地存储,并停止iCloud仍然响应)。



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



为了完整性,迁移代码基于其他堆栈溢出问题,但我粘贴这里为了方便起见:

   - (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(@当前商店URL(iCloud到本地迁移之前):%@,[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(@当前商店URL(iCloud到本地迁移后):%@,[storeURL description]);

NSLog(@完成重新载入);

[[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(@在持久存储中,iCloud在应用设备中启用,但尚未在应用中,而不是在最新版本上);

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

}
else if((iCloud)&&([[NSUserDefaults standardUserDefaults] boolForKey:@iCloudOn])&&([[NSUserDefaults standardUserDefaults] boolForKey:@ OnLatestVersion]))
{
NSLog(@在持久存储中,iCloud已启用,我们使用iCloud从教程,我们是最新版本);
NSURL * cloudURL = [self grabCloudPath:@iCloud];
options = @ {NSMigratePersistentStoresAutomaticallyOption:@YES,
NSInferMappingModelAutomaticallyOption:@YES,
NSPersistentStoreUbiquitousContentURLKey:cloudURL,NSPersistentStoreUbiquitousContentNameKey:@EnvyCloud};


}
else if((iCloud)&&(![[NSUserDefaults standardUserDefaults] boolForKey:@iCloudOn])&&([[NSUserDefaults标准的UserDefaults] boolForKey:@OnLatestVersion]))
{
NSLog(@在持久存储,iCloud启用,我们的最新版本,btu我们不使用icloud App);

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

}
else
{
NSLog(@iCloud is not 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然后决定NOT使iCloud不再在这个特定设备上,iCloud通知被删除,存储从iCloud Store迁移到本地存储,并设置一个NSUserDefaults。在下一次启动应用程序..第三个if语句在 persistentStoreCoordinator 中的值为true,这是正确的说我们是最新版本,iCloud启用(在设备),但不是在应用程序,但然后它显示应用程序,绝对没有任何条目,有点像新鲜。



如何解决这个问题并返回刚刚迁移的商店?



<任何想法都会非常感激。

解决方案

应用程序启动时没有数据指向持久存储协调器。



看起来像选项字典的评估是正常的,但在任一结果中,您始终使用相同的持久存储URL设置协调器。



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



根据您的评估结果设置协调员以及各自的网址,希望您在应用启动时看到您的数据。


Based on the question here: Migrate iCloud data to Local store and stopping iCloud from still responding regard moving an iCloud store over to a local store and making sure the iCloud notifications are disabled, I have the next scenario that I am stuck on.

Issue

Right now, when the user runs the app on the first device, they're asked at the start if they want to enable iCloud. If they select yes, the data is migrated over to iCloud. If the user connects in a second device, they're asked if they want to use iCloud at the start and if they select yes, data from the first device is synchronised across.

If the user on the second device decides they don't want to use iCloud anymore, they can navigate and turn off iCloud within the app for that device specifically. This in the back-end will migrate their data from the iCloud store to the Local Store. From the users point of view, all of their data is there (whether it's stored in the cloud or local doesn't matter to the user at this point).

The issue is when I migrate my data across, it successfully migrates over to the local iCloud store and successfully stops listening for iCloud notifications. That aspect works and that's in the stack overflow question that I previously asked (Migrate iCloud data to Local store and stopping iCloud from still responding).

The specific issue is that when the user re-launches the app, the app is now empty with no data. This is of course not the desired effect.

For completeness, the "migration code" is based in the other stack overflow question but I'm pasting it here for convenience:

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

All of the magic happens in the persistentStoreCoordinator.. it's messy, but I need to get this part working and then this can be cleaned up:

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

So in the scenario where the user enables iCloud in the app and then decides NOT to have iCloud anymore on this particular device, the iCloud notifications get removed, the store is migrated from the iCloud Store to the local store and a NSUserDefaults is set. On the next launch of the app.. the 3rd if statement evaluates as true in the persistentStoreCoordinator which is correctly saying we're on the latest version, iCloud is enabled (in the device) but not in the app, but then it shows the app with absolutely no entries whatsoever, kind of like starting fresh.

How do I overcome this and return the store that was just recently migrated?

Any thoughts would seriously be greatly appreciated.

解决方案

No data upon app launch points to the persistent store coordinator.

Looks like the evaluation for the options dictionary is fine, but in either outcome you're always setting up the coordinator with the same persistent store URL.

Likewise, in the migration routine, you're migrating the persistent store object, but with the same URL. That can't work, as that's where the actual files are saved. You need a different URL for the local store and for the iCloud store, then you can correctly migrate the data across and choose to delete the URL you no longer need (after removing the store from the coordinator).

Setup the coordinator with the respective URL, depending on the outcome of your evaluation - and hopefully - you should see your data upon app launch.

这篇关于将iCloud Store迁移到本地存储,并确保每个应用程序启动时都有数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆