我在这里关于核心数据标准migratioin的教程:
http://mipostel.com/index.php/home/70-core-data-migration-standard-migration-part-2
然后在这里用多次传递来做这件事:
Example or explanation of Core Data Migration with multiple passes?
这给了我生成的代码:
- (NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext != nil) {
return managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [TICDSSynchronizedManagedObjectContext new];
[managedObjectContext setPersistentStoreCoordinator: coordinator];
}
return managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel != nil) {
return managedObjectModel;
}
// managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];
NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"EntryDatabase" ofType:@"momd"];
NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSString *storePath = [[self applicationDocumentsDirectory]
stringByAppendingPathComponent:@"CoreDataStore.sqlite"];
NSFileManager *fileManager = [NSFileManager defaultManager];
// If the expected store doesn't exist, copy the default store.
NSLog(@"file exists at path: %@, %i", storePath, [fileManager fileExistsAtPath:storePath]);
if (![fileManager fileExistsAtPath:storePath]) {
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"CoreDataStore" ofType:@"sqlite"];
if (defaultStorePath) {
[fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
}
}
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSURL *storeUrl = [NSURL fileURLWithPath:storePath];
NSError *error;
NSDictionary *pscOptions = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:NO], NSInferMappingModelAutomaticallyOption,
nil];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeUrl
options:pscOptions
error:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
}
return persistentStoreCoordinator;
}
- (BOOL)checkForMigration
{
BOOL migrationSuccess = NO;
NSString *storeSourcePath = [[self applicationDocumentsDirectory]
stringByAppendingPathComponent:@"CoreDataStoreNew.sqlite"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:storeSourcePath]) {
//Version 2 SQL has not been created yet, so the source is still version 1...
storeSourcePath = [[self applicationDocumentsDirectory]
stringByAppendingPathComponent:@"CoreDataStore.sqlite"];
}
NSURL *storeSourceUrl = [NSURL fileURLWithPath: storeSourcePath];
NSError *error = nil;
NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator
metadataForPersistentStoreOfType:NSSQLiteStoreType
URL:storeSourceUrl
error:&error];
if (sourceMetadata) {
NSString *configuration = nil;
NSManagedObjectModel *destinationModel = [self.persistentStoreCoordinator managedObjectModel];
//Our Source 1 is going to be incompatible with the Version 2 Model, our Source 2 won't be...
BOOL pscCompatible = [destinationModel isConfiguration:configuration compatibleWithStoreMetadata:sourceMetadata];
NSLog(@"Is the STORE data COMPATIBLE? %@", (pscCompatible==YES) ?@"YES" :@"NO");
if (pscCompatible == NO) {
migrationSuccess = [self performMigrationWithSourceMetadata:sourceMetadata toDestinationModel:destinationModel];
}
}
else {
NSLog(@"checkForMigration FAIL - No Source Metadata! \nERROR: %@", [error localizedDescription]);
}
return migrationSuccess;
}
- (BOOL)performMigrationWithSourceMetadata :(NSDictionary *)sourceMetadata
toDestinationModel:(NSManagedObjectModel *)destinationModel
{
BOOL migrationSuccess = NO;
//Initialise a Migration Manager...
NSManagedObjectModel *sourceModel = [NSManagedObjectModel mergedModelFromBundles:nil
forStoreMetadata:sourceMetadata];
//Perform the migration...
if (sourceModel) {
NSMigrationManager *standardMigrationManager = [[NSMigrationManager alloc]
initWithSourceModel:sourceModel
destinationModel:destinationModel];
NSArray *mappingModelNames = [NSArray arrayWithObjects:@"StepOne", @"StepTwo", nil];
NSDictionary *sourceStoreOptions = nil;
NSString *destinationStorePath = [[self applicationDocumentsDirectory]
stringByAppendingPathComponent:@"CoreDataStoreNew.sqlite"];
NSURL *destinationStoreURL = [NSURL fileURLWithPath: destinationStorePath];
NSString *destinationStoreType = NSSQLiteStoreType;
NSDictionary *destinationStoreOptions = nil;
for (NSString *mappingModelName in mappingModelNames) {
NSError *error;
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:mappingModelName withExtension:@"cdm"];
NSMappingModel *mappingModel = [[NSMappingModel alloc] initWithContentsOfURL:fileURL];
migrationSuccess = [standardMigrationManager migrateStoreFromURL:destinationStoreURL
type:NSSQLiteStoreType
options:sourceStoreOptions
withMappingModel:mappingModel
toDestinationURL:destinationStoreURL
destinationType:destinationStoreType
destinationOptions:destinationStoreOptions
error:&error];
NSLog(@"Error: %@", error);
}
}
return migrationSuccess;
}
尽管如此,应用程序内存耗尽并在persistentStoreCoordinator
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeUrl
options:pscOptions
error:&error]) {
答案 0 :(得分:0)
我记得我也遵循了这个教程。
实际上我发现这不是正确的做法。那么你是否已经阅读了该教程的最后一条评论并尝试删除提到的行?也许这可以解决你的情况?
无论如何,在我的情况下,我意识到(在遵循本教程之后,修改没有帮助),有一个更简单的方法。
在你的情况下,我不知道,如果这个小修改没有解决它,我真的会寻找另一个参考 - 因为这真的不是正确的方法,并导致你错误的方向,因为它尝试自己做所有事情而不是使用Apple核心数据迁移程序背后的逻辑,因为我发现了困难的方法。
答案 1 :(得分:0)
几年前我解决的问题主要是从一个存储库中取出一个子树,然后在另一个存储库中复制,我所做的应该适合你。我在Mac上执行此操作因此内存不是问题,但根据核心数据编程指南“减少内存开销”,通过适当的错误和减少内存,您应该能够使其工作。
以下解决方案基于MOM并非完全不同的假设。让我为现有的上下文引入术语“A”,为新的上下文引入“B”。
1)第一步是复制B中A中的每个对象。如果该类保持不变,那么很好。这意味着对于每个对象,您需要一个实体中所有值的列表。我建议使用键 - 每个实体类型的属性键数组,这将使代码更容易(如果可以)。否则,您实际上可以从MOM获取密钥 - 这就是我在旧代码中所做的。
现在关键步骤 - 你必须创建一个翻译词典(也许你需要两个 - 我做了),对于A中的每个实体你都知道'B'中的相应实体。您可以使用'objectID'属性(但是对于B不执行保存,直到您保存此值更改为止)。
2)现在您已经完全重新创建了所有实体,您需要“连接”它们 - 因此所有关系都已正确设置。再次,为每个实体类型创建一些键数组,然后在循环中查看“A”中的每个关系,获取它指向的实体,使用转换表在“B”中查找相应的关系,并设置'B'中的值。
瞧!完成。您显然会添加删除是否执行上述操作以镜像A-B中的更改。
我再一次不需要担心Mac上的内存,所以不需要花钱来记忆。我相信错误('refreshObject:mergeChanges:')会帮助你,但再也没有必要这样做(即便如此,可能只是大尺寸的对象)。