我有一个使用 Core Data 来持久化信息的应用程序。我正在向我的应用程序添加一个共享扩展,这将需要访问相同的数据,因此我需要将我的持久存储从我的应用程序的沙箱移动到应用程序组沙箱中。正如Update Core Data store location to support App Groups中所建议的那样,我正在使用迁移来做到这一点。问题是我的多对多关系在迁移过程中消失了。
我能够从具有核心数据的基本单视图应用程序开始重新创建问题。连接一个按钮以在默认的 managedObjectContext 中创建对象(我必须添加一个队列),并显示一条状态消息:
AppDelegate * delegate = [UIApplication sharedApplication].delegate;
[delegate.managedObjectContext performBlock:^{
Book * book1 = [[Book alloc] initWithEntity:[NSEntityDescription entityForName:@"Book" inManagedObjectContext:delegate.managedObjectContext] insertIntoManagedObjectContext:delegate.managedObjectContext];
Book * book2 = [[Book alloc] initWithEntity:[NSEntityDescription entityForName:@"Book" inManagedObjectContext:delegate.managedObjectContext] insertIntoManagedObjectContext:delegate.managedObjectContext];
Topic * topic1 = [[Topic alloc] initWithEntity:[NSEntityDescription entityForName:@"Topic" inManagedObjectContext:delegate.managedObjectContext] insertIntoManagedObjectContext:delegate.managedObjectContext];
Topic * topic2 = [[Topic alloc] initWithEntity:[NSEntityDescription entityForName:@"Topic" inManagedObjectContext:delegate.managedObjectContext] insertIntoManagedObjectContext:delegate.managedObjectContext];
Topic * topic3 = [[Topic alloc] initWithEntity:[NSEntityDescription entityForName:@"Topic" inManagedObjectContext:delegate.managedObjectContext] insertIntoManagedObjectContext:delegate.managedObjectContext];
book1.title = @"Breadbaker's Apprentice";
book1.authorName = @"Peter Reinhart";
book2.title = @"Tartine Bread";
book2.authorName = @"Chad Robertson";
topic1.topicName = @"Bread";
topic1.topicPriority = [NSDecimalNumber decimalNumberWithString:@"0.9"];
[topic1 addBooksObject:book2];
topic2.topicName = @"Baking";
topic2.topicPriority = [NSDecimalNumber decimalNumberWithString:@"0.7"];
[topic2 addBooksObject:book1];
[topic2 addBooksObject:book2];
topic3.topicName = @"San Francisco";
topic3.topicPriority = [NSDecimalNumber decimalNumberWithString:@"0.2"];
[topic3 addBooksObject:book2];
NSError * saveError;
if(![delegate.managedObjectContext save:&saveError])
{
NSLog(@"Failed to save for some reason: %@", saveError.debugDescription);
dispatch_async(dispatch_get_main_queue(), ^{
self.statusLabel.text = [NSString stringWithFormat:@"Failed to save for some reason: %@", saveError.debugDescription];
});
}
else
{
dispatch_async(dispatch_get_main_queue(), ^{
self.statusLabel.text = @"OK, added objects";
});
}
}];
在模拟器中运行时,我可以在命令行上使用 sqlite3 来检查 SQLite 数据库——特别是 Core Data 创建的 Z_1TOPICS 链接表——在添加这些对象后:
sqlite> .tables
ZBOOKS ZTOPICS Z_1TOPICS Z_METADATA Z_PRIMARYKEY
sqlite> SELECT * from Z_1TOPICS;
1|3
1|2
2|2
2|3
2|1
一切看起来都差不多。接下来,设置第二个按钮以将持久存储迁移到 App Group 目录:
AppDelegate * delegate = [UIApplication sharedApplication].delegate;
NSURL *newStoreURL = [[delegate groupDocumentsDirectory] URLByAppendingPathComponent:@"Migration_Bug_Demonstration.sqlite"];
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Migration_Bug_Demonstration" withExtension:@"momd"];
NSManagedObjectModel * managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
NSPersistentStoreCoordinator *tempCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: managedObjectModel];
NSURL *oldStoreURL = [[delegate applicationDocumentsDirectory] URLByAppendingPathComponent:@"Migration_Bug_Demonstration.sqlite"];
NSPersistentStore *sourceStore = nil;
NSPersistentStore *destinationStore = nil;
NSDictionary *RWoptions = @{NSMigratePersistentStoresAutomaticallyOption: @YES,
NSInferMappingModelAutomaticallyOption: @YES};
NSDictionary * ROoptions = @{NSReadOnlyPersistentStoreOption:@YES,NSMigratePersistentStoresAutomaticallyOption: @YES,
NSInferMappingModelAutomaticallyOption: @YES};
NSError * error;
// Add the source store
if (![tempCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:oldStoreURL options:ROoptions error:&error]){
// Handle the error
NSLog(@"Error adding old store: %@ -- %@", error, error.userInfo);
}
else
{
sourceStore = [tempCoordinator persistentStoreForURL:oldStoreURL];
if (sourceStore != nil){
// Perform the migration
destinationStore = [tempCoordinator migratePersistentStore:sourceStore toURL:newStoreURL options:RWoptions withType:NSSQLiteStoreType error:&error];
if (destinationStore == nil){
NSLog(@"Error migrating store: %@ -- %@", error, error.userInfo);
// Handle the migration error
dispatch_async(dispatch_get_main_queue(), ^{
self.statusLabel.text = [NSString stringWithFormat:@"Failed to migrate: %@", error.debugDescription];
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
self.statusLabel.text = @"OK, moved store";
});
}
}
}
大部分代码直接来自上面链接的问题。Books 和 Topics 之间的关系没有迁移,但对象本身是:
sqlite> .tables
ZBOOKS ZTOPICS Z_1TOPICS Z_METADATA Z_PRIMARYKEY
sqlite> SELECT * FROM Z_1TOPICS;
sqlite> SELECT * FROM ZTOPICS;
1|2|1|0.2|San Francisco
2|2|1|0.7|Baking
3|2|1|0.9|Bread
sqlite> SELECT * FROM ZBOOKS;
1|1|1|Peter Reinhart|Breadbaker's Apprentice
2|1|1|Chad Robertson|Tartine Bread
实际上,在运行所有这些之前使用“-com.apple.CoreData.SQLDebug 1”启动参数,我可以验证 Core Data 正在写入 ZTOPICS 和 ZBOOKS 表,但从未写入 Z_1TOPICS 表。
所以现在我被困住了。我什至不确定我还能做些什么来调查这个问题——也许执行自定义迁移以便我可以观察(甚至手动执行)关系迁移?我可能只是尝试手动移动持久性存储文件(即使这是不可以),因为我不确定我还能做什么。谢谢你的时间。