将现有Core Data迁移到iCloud

时间:2014-05-15 09:54:57

标签: ios iphone core-data icloud nspersistentstore

我有一个简单的应用程序,UITableView由用户在不同的视图中填充一些UITextFields来填充。此信息会保存到CoreDataUITableView会使用NSFetchedResultsController进行更新。

我现在正在将iCloud同步引入我的环境。参考之前提出的问题:Existing Core Data Database Not Uploading to iCloud When Enabling iCloud On My App,我仍然遇到问题但是用新代码更新问题太麻烦了。我指的是WWDC 2013 CoreData会话以及this。因为我的应用只是iOS 7。我是iCloud开发的新手,也是一名中级程序员。

当我从App Store(非iCloud)版本更新到开发(iCloud)版本时,我将现有数据迁移到iCloud时遇到很大困难。新数据完美同步。

据我所知,我需要在不使用iCloud的情况下将我现有的商店转移到iCloud,但它只是不适合我。

这里有一些代码来说明我正在做的事情:

更新

我已经完成并考虑了这一点并删除了多余的代码。

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

     NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Planner.sqlite"];
     NSFileManager *fm = [NSFileManager defaultManager];
     NSURL *url = [fm URLForUbiquityContainerIdentifier:nil];
     NSError *error = nil;
     _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

     if (url)
     {
         NSLog(@"iCloud is enabled");
         NSDictionary *options = @{
                                   NSMigratePersistentStoresAutomaticallyOption : @YES,
                                   NSInferMappingModelAutomaticallyOption : @YES,
                                   };

         NSPersistentStore *localStore = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error];

         [_persistentStoreCoordinator migratePersistentStore:localStore toURL:[self iCloudURL] options:[self iCloudStoreOptions] withType:NSSQLiteStoreType error:&error];

     }
     else
     {
         NSLog(@"iCloud is not enabled");
         NSDictionary *options = @{
                                   NSMigratePersistentStoresAutomaticallyOption : @YES,
                                   NSInferMappingModelAutomaticallyOption : @YES
                                   };

         if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[self iCloudURL] options:options error:&error])
         {
             NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
             abort();

         }

     }

     dispatch_async(dispatch_get_main_queue(), ^{

    [[NSNotificationCenter defaultCenter] postNotificationName:@"Reload" object:self userInfo:nil];
});

     return _persistentStoreCoordinator;
}

我不再调用migrateLocalStoreToiCloud方法,但它在这里供参考:

/*-(void)migrateLocalStoreToiCloud
{
    //assuming you only have one store.
    NSPersistentStore *store = [[_persistentStoreCoordinator persistentStores] firstObject];
    NSPersistentStore *newStore = [_persistentStoreCoordinator migratePersistentStore:store
                                                                                toURL:[self iCloudURL]
                                                                              options:[self iCloudStoreOptions]
                                                                             withType:NSSQLiteStoreType
                                                                                error:nil];
    [self reloadStore:newStore];
}

* /

storeURLstoreOptionsiCloudURLiCloudStoreOptions代码为:

- (NSURL *)iCloudURL
{
    NSFileManager *fm = [NSFileManager defaultManager];
    NSURL *url = [fm URLForUbiquityContainerIdentifier:nil];
     if (url) {
     NSLog(@"iCloud access at %@", url);
     } else {
     NSLog(@"No iCloud access");
     }
    return url;
}

-(NSURL *)storeURL{
    return [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Planner.sqlite"];
}


-(NSDictionary *)storeOptions{
    NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
    [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
    [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
    return options;
}

-(NSDictionary *)iCloudStoreOptions{
    NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
    [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
    [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
    [options setObject:@"PlannerStore" forKey:NSPersistentStoreUbiquitousContentNameKey];
    return options;
}

问题

当我完全按原样运行此代码时,虽然数据存在,但我并未在控制台中使用Local Storage : 10

如果我更改persistentStoreCoordinator首先添加persistentStore以使用[self iCloudStoreOptions]作为选项,Using Local Storage 10会显示,但数据不会显示在migrateLocaltoiCloud上设备。

我遵循这里的指导,我尝试了多种代码变体,包括不在reloadStore方法中删除任何persistentStore,但我完全被卡住了。

我看过很多帖子,但似乎我找不到将数据从非iCloud版本迁移到iCloud版本的人,而且我找到的例子中没有代码。

我已经查看了this虽然它是一个很棒的代码集,但我已经下载了代码并遵循了那些它不会删除任何persistentStore的指南,但它仍然不会。为我工作。我无法想象我想要实现的目标非常复杂。我只需要获取现有的非iCloud数据并将其迁移到iCloud。

更新

阅读Apple的指南:https://developer.apple.com/LIBRARY/ios/documentation/DataManagement/Conceptual/UsingCoreDataWithiCloudPG/UsingSQLiteStoragewithiCloud/UsingSQLiteStoragewithiCloud.html#//apple_ref/doc/uid/TP40013491-CH3-SW2我可以看到我的persistentStore方法目前在移除persistentStoreCoordinator等方面有误,但我可以'弄清楚如何解决它。如果我从DidChangeNotification调用此内容,是否会以某种方式干扰{{1}}?

我真的坚持这一点,我很感激任何正确方向的指导

1 个答案:

答案 0 :(得分:1)

我在这里提供一个答案,因为它比更新问题更清楚,经过大量调试后,我在某种程度上有了这个工作。

通过调试addPersistentStoremigratePersistentStore行代码,我想出了:

 NSPersistentStore *localStore = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error];

 NSLog(@"The localStore is %@", localStore);

 NSPersistentStore *migratedStore = [_persistentStoreCoordinator migratePersistentStore:localStore toURL:[self iCloudURL] options:[self iCloudStoreOptions] withType:NSSQLiteStoreType error:&error];

 NSLog(@"The migrationStore is %@", migratedStore); 

The NSLog value of localStore is: The localStore is <NSSQLCore: 0x13451b100> (URL: file:///var/mobile/Applications/DDB71522-C61D-41FC-97C7-ED915D6C46A4/Documents/Planner.sqlite)

The NSLog value of migratedStore is: (null)

通过调试,我可以看到基本相同的东西,migrateStore始终为null。

我稍微更改了代码:

 NSPersistentStore *migratedStore = [_persistentStoreCoordinator migratePersistentStore:localStore toURL:storeURL options:[self iCloudStoreOptions] withType:NSSQLiteStoreType error:&error];

要将URL作为storeURL,突然之间,一切都开始有效了,其中storeURL:

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

我的输出是:

The localStore is <NSSQLCore: 0x14ee09b50> (URL: file:///var/mobile/Applications/CC0F7DA0-251F-46D6-8E43-39D63062AED2/Documents/Planner.sqlite)
[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](771): CoreData: Ubiquity:  mobile~5BD59259-7758-42FB-986F-DDD173F75ED3:EnStor
The migrationStore is <NSSQLCore: 0x157e260b0> (URL: file:///var/mobile/Applications/A08D183D-ECD4-4E72-BA64-D21727DE7A3E/Documents/CoreDataUbiquitySupport/mobile~CB6C3699-8BF1-47DB-9786-14BCE1CD570A/EnStor/771D2B0B-870A-428E-A9A8-5DAE1295AF53/store/Planner.sqlite)

使用本地存储从1变为0,应用程序的App Store版本中的数据继续通过迁移到新版本。这是我在升级后第一次运行应用程序时的输出。

这是个好消息。

每次我运行应用程序时,数据都会继续迁移,因此我最终会得到重复的结果。

问题还在于,在添加新设备时,它不会将信息下载到新设备。

我不太明白为什么使用storeURL作为migratePersistentStore的url工作?

我也不希望每个新设备基本上添加一个新的持久性存储(如果已经存在)并且我不知道如何解决这个问题并且我也不希望一次又一次地进行迁移。它应该只发生一次。

我到了那里,但还有很多工作要做!