4

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

我现在将 iCloud 同步引入我的环境。参考之前提出的问题:Existing Core Data Database Not Uploading to iCloud When Enabling iCloud On My App,我仍然遇到问题,但是用我的新代码更新这个问题太麻烦了。我专门指的是WWDC 2013 CoreDataSessions 以及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];
}

*/

storeURL和代码storeOptions是:iCloudURLiCloudStoreOptions

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

问题

当我完全按原样运行此代码时,尽管数据在那里,但我根本不会在控制台中显示 UsingLocal Storage : 1和。0

如果我更改persistentStoreCoordinator它首先添加persistentStore 以[self iCloudStoreOptions]用作选项的位置,Using Local Storage 1然后0显示,但数据不在设备上。

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

我已经阅读了很多帖子,但似乎我找不到将数据从非 iCloud 版本迁移到 iCloud 版本的人,并且我找到了示例,没有代码。

对此进行了研究,虽然它是一个很棒的代码集,但我已经下载了代码并遵循了那些不会删除任何 persistentStore 但它仍然对我不起作用的准则。我无法想象我想要实现的目标非常复杂。我只需要获取现有的非 iCloud 数据并将其迁移到 iCloud。

更新

通过阅读 Apple 的指南:https ://developer.apple.com/LIBRARY/ios/documentation/DataManagement/Conceptual/UsingCoreDataWithiCloudPG/UsingSQLiteStoragewithiCloud/UsingSQLiteStoragewithiCloud.html#//apple_ref/doc/uid/TP40013491-CH3-SW2我可以看到我的migrateLocaltoiCloud方法目前在删除persistentStore等方面是错误的,但我不知道如何修复它。如果我从 中调用它persistentStoreCoordinator,它会以某种方式干扰DidChangeNotification吗?

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

4

1 回答 1

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 始终为空。

我稍微更改了代码:

 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 有效?

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

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

于 2014-05-16T13:29:18.623 回答