【问题标题】:Migrating iCloud store to local将 iCloud 商店迁移到本地
【发布时间】:2014-02-12 15:03:54
【问题描述】:

迁移在模拟器上运行良好。但是在设备上,我没有看到任何错误消息,但迁移的存储是空的。

NSDictionary *iCloudOptions = @{
    NSPersistentStoreUbiquitousContentNameKey : @"iCloudNimbleStore",
    NSPersistentStoreUbiquitousContentURLKey : @"transactions_logs",
    NSMigratePersistentStoresAutomaticallyOption : @YES,
    NSInferMappingModelAutomaticallyOption : @YES
};
NSDictionary *localOptions = @{NSMigratePersistentStoresAutomaticallyOption : @YES,
    NSInferMappingModelAutomaticallyOption : @YES
};
if (![[NSFileManager defaultManager]fileExistsAtPath:self.storeURL.path]) {
    @synchronized(@"Migration")
    {
        // thread-safe code
        if ([[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]) {
            NSLog(@"iCloud");
            [self migrateStoreFromURL:[self nb_URLToStoreWithFilename:[self nb_appName]]options:iCloudOptions];
        }else{
            [self migrateStoreFromURL:[self nb_URLToStoreWithFilename:[NSString stringWithFormat:@"%@.sqlite", [self nb_appName]]] options:localOptions];
            //
            [self migrateStoreFromURL:[self nb_URLToOldStoreWithFilename] options:localOptions];
        }
    }
}

NSDictionary *options = @{
    NSMigratePersistentStoresAutomaticallyOption:@YES
    ,NSInferMappingModelAutomaticallyOption:@YES
};
NSError *error = nil;
[_coordinator lock];
_store = [_coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[self storeURL] options:options error:&error];
[_coordinator unlock];
if (!_store) {
    UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Loading Fail" message:[NSString stringWithFormat:@"Failed to add store. Error: %@", error] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    [alert show];
    NSLog(@"Failed to add store. Error: %@", error);abort();
} else {
    UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Loading Success" message:[NSString stringWithFormat:@"Successfully added store: %@", _store] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    [alert show];
    NSLog(@"Successfully added store: %@", _store);
    if (_store && !error) {
        // Encrypt the password database
        NSError *encrError;
        NSDictionary *fileAttributes = [NSDictionary dictionaryWithObject:NSFileProtectionComplete forKey:NSFileProtectionKey];
        if (![[NSFileManager defaultManager] setAttributes:fileAttributes ofItemAtPath:self.storeURL.path error:&encrError]){
            NSLog(@"Unresolved error with password store encryption %@, %@", encrError, [encrError userInfo]); 
            abort();
        }else {NSLog(@"Encrypted");}
    }
}

这是迁移过程:

- (void)migrateStoreFromURL:(NSURL *)oldStoreURL options:(NSDictionary *)oldOptions{
if (debug==1) {
    TFLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
}
if (_store)
{
    NSLog(@"NOT NEEDED");
    return;
}

UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Migration" message:[NSString stringWithFormat:@"Found old store at %@",oldStoreURL.path] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
[alert show];

NSFileManager *fileManager = [NSFileManager defaultManager];

if (![fileManager fileExistsAtPath:self.storeURL.path]) {
    NSDictionary *options =
    @{
      NSMigratePersistentStoresAutomaticallyOption:@YES
      ,NSInferMappingModelAutomaticallyOption:@YES
      };
    NSError *error = nil;
    [_coordinator lock];
    NSPersistentStore *srcPS = [_coordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                                                  configuration:nil
                                                                                            URL:oldStoreURL
                                                                                        options:oldOptions
                                                                                          error:&error];

    _store = [_coordinator migratePersistentStore:srcPS
                                                                             toURL:self.storeURL
                                                                           options:options
                                                                          withType:NSSQLiteStoreType
                                                                             error:&error];
    [_coordinator unlock];
    if (_store && !error) {
        UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Migration Success" message:[NSString stringWithFormat:@"Old store successfully migrated from %@",oldStoreURL.path] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
        [alert show];
        // Encrypt the password database
        NSError *encrError;
        NSDictionary *fileAttributes = [NSDictionary dictionaryWithObject:NSFileProtectionComplete forKey:NSFileProtectionKey];
        if (![[NSFileManager defaultManager] setAttributes:fileAttributes ofItemAtPath:self.storeURL.path error:&encrError]){
            UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Encryption Error" message:[NSString stringWithFormat:@"Unresolved error with password store encryption %@, %@", encrError, [encrError userInfo]] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
            [alert show];
        }

    }else{
        UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Migration Error" message:error.localizedDescription delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
        [alert show];
    }

}

更新:我检查了新迁移的商店的大小,它是0。最奇怪的是_store && !error是真的。我还尝试将NSPersistentStoreRemoveUbiquitousMetadataOption: @YES 添加到迁移选项中,但它并没有改变任何东西。

更新。 2 我认为设备上的 iCloud 商店网址在加载之前为零。我需要一些解决方法才能等到它完成。

【问题讨论】:

  • 您等待迁移完成的时间是否足够长?打开 Core Data 日志记录并监控 Xcode 中的 iCloud 网络流量,看看发生了什么。
  • 不,我不等。问题是在设备上迁移后我得到了空商店。在启用了 iCloud 的模拟器上一切顺利。从 TestFlight 安装更新时,我无法使用日志记录。

标签: objective-c core-data ios7 icloud


【解决方案1】:

我不是 100% 确定我了解您要对迁移做什么。通过迁移在空存储中播种数据是很常见的,但看起来您正在尝试将数据从 iCloud 迁移到本地存储中。是对的吗?你不应该这样做。 iCloud 应该会自动将来自其他设备的数据添加到您的存储中。

这条线也不对:

NSPersistentStoreUbiquitousContentURLKey : @"transactions_logs",

我认为您想在那里使用指向 iCloud 容器内的事务日志目录的 URL。例如。

NSURL *containerURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
NSURL *url = [containerURL URLByAppendingPathComponent:@"transactions_logs"];

使用 iCloud 时,重要的是要意识到数据不会立即传输。可能需要一段时间才能到达,并且您的应用程序实际上无法确定是否有数据到来。您可以使用元数据查询来监控元数据,但即便如此,通常也会在其他设备上的数据已经生成之后的一段时间内到达。

因此,简单地在无处不在的容器中查找数据并没有多大帮助,因为可能有数据,也可能没有数据。你只是不知道,你必须在考虑到这个假设的情况下开发你的方法,以便它可以处理任何延迟。

使 iCloud 同步与 Core Data 一起工作所需的迁移是混乱且不必要的。您可能更有可能使用自动执行该操作的框架(例如 Core Data Ensembles)使事情正常运行。 (披露:我是 Ensembles 的开发者。)

【讨论】:

  • 我试图用你的行替换内容 url,但它没有帮助。由于 iOS7 这条线是完全有效的(它是在 WWDC2013、Core Data 和 iCloud 讲座中介绍的)。我使用了 Nimble 框架,该框架是专门为使用 iOS7 iCloud 同步优势而编写的,但是它在数据模型版本控制上出现问题,所以我决定将商店迁移到本地。迁移工作正常,在 Xcode 中测试时,但当我在 iPad 上测试时,它会创建 0 大小的文件而没有任何错误...
  • 您确定迁移的文件实际上是空的吗?你是如何测试的?您是在查看存储文件大小,还是从存储中获取对象?我问的原因是,使用新的日志功能,如果缓冲的数据没有达到某个级别,sqlite 存储可以保持为空。
  • 是的,我使用 AlertView 进行了测试,通过 TestFlight 安装时它为零。就在一分钟前,我决定检查该应用程序的先前版本,当我通过 TestFlight 发送它时,它的 store 也是 nil。所以这次迁移似乎没什么问题,但 TestFlight 更新开始删除文档数据。我前段时间更改了配置文件,也许这就是原因。
猜你喜欢
  • 2014-10-02
  • 1970-01-01
  • 1970-01-01
  • 2016-04-29
  • 2012-09-27
  • 1970-01-01
  • 2014-09-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多