将 iCloud 商店迁移到本地
Posted
技术标签:
【中文标题】将 iCloud 商店迁移到本地【英文标题】:Migrating iCloud store to local 【发布时间】: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 安装更新时,我无法使用日志记录。 【参考方案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 更新开始删除文档数据。我前段时间更改了配置文件,也许这就是原因。以上是关于将 iCloud 商店迁移到本地的主要内容,如果未能解决你的问题,请参考以下文章
将 PersistentStoreCoordinator 从本地迁移到 iCloud 时数据重复
在迁移时从 iCloud 迁移到本地商店崩溃的应用程序“对象不能为零” - 使用 Core Data