【问题标题】:Migrating an iCloud Store to a Local Store and making sure the data is there through each app launch将 iCloud 商店迁移到本地商店并确保数据在每次应用启动时都存在
【发布时间】:2014-10-02 00:01:12
【问题描述】:

基于此处的问题: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 商店迁移到本地商店,并且 NSUserDefaults 是放。在应用程序的下一次启动时.. 第 3 个 if 语句在 persistentStoreCoordinator 中评估为 true,这正确地表示我们使用的是最新版本,iCloud 已启用(在设备中)但未在应用程序中,但随后它显示绝对没有任何条目的应用程序,有点像重新开始。

我该如何克服这个问题并退回刚刚迁移的商店?

任何想法将不胜感激。

【问题讨论】:

    标签: ios objective-c core-data icloud


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 非常感谢 Jay 在这里的回答,再一次,您帮助我找到了解决方案,我真的很感激。考虑到您的回答,我继续调整我的迁移代码,使其与我从本地迁移到 iCloud 商店的方式完全相同,并确保对本地/iCloud 使用单独的 URL。有了它,并设置了适当的选项,我现在可以从 iCloud 迁移到本地存储,并在每次启动时查看数据。非常感谢您的帮助杰!
    • 好消息!这一切都在一起了:-)
    • amitsbajaj 你能发布你的最终方法吗?最终对你有用的是什么?提前致谢!
    • 是的,共享代码并将其标记为答案会很好,这也是本网站的目的。那么,@Jay Versluis,你能分享一下代码吗?
    猜你喜欢
    • 1970-01-01
    • 2016-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多