标准核心数据迁移,多次通过无效

时间:2012-09-23 13:00:50

标签: iphone objective-c ios core-data core-data-migration

我在这里关于核心数据标准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]) {

2 个答案:

答案 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:')会帮助你,但再也没有必要这样做(即便如此,可能只是大尺寸的对象)。