1

我在这里遵循了关于核心数据标准迁移的教程:

http://mipostel.com/index.php/home/70-core-data-migration-standard-migration-part-2

然后在这里进行多次传递:

多遍核心数据迁移的示例或解释?

这给了我这里的结果代码:

- (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]) {
4

2 回答 2

0

我记得我也跟着这个教程。

其实我发现这不是正确的做法。顺便说一句,您是否阅读了该教程的最后一条评论并尝试删除提到的行?也许这可以解决您的情况?

无论如何,就我而言,我意识到(在遵循本教程之后,修改没有帮助)有一种更简单的方法。

但是,在你的情况下,我不知道,如果这个小小的修改不能解决它,我真的会寻找另一个参考 - 因为这确实不是正确的做法,并且会导致你走向错误的方向,因为它试图做一切本身,而不是使用苹果核心数据迁移过程背后的逻辑,因为我发现很难。

于 2012-09-23T14:45:57.903 回答
0

几年前我解决的问题是从一个存储库中取出一个子树并将其复制到另一个存储库中,我所做的应该对你有用。我在 Mac 上执行此操作,因此内存不是问题,但是通过按照核心数据编程指南“减少内存开销”进行适当的故障排除和减少内存,您应该能够使其正常工作。

以下解决方案基于 MOM 并非完全不同的假设。让我介绍现有上下文的术语“A”和新上下文的“B”。

1)第一步是将A中的每个对象复制到B中。如果类保持不变,那很好。这意味着对于每个对象,您都需要一个来自实体的所有值的列表。我建议使用键 - 每个实体类型的属性键数组,这将使编码更容易(如果可以的话)。否则,您实际上可以从 MOM 获取密钥——这就是我在旧代码中所做的。

现在是关键步骤 - 您必须创建一个翻译词典(也许您需要两个 - 我做了),对于 A 中的每个实体,您都知道“B”中的对应一个。您可以使用“objectID”属性(但对于 B,不要保存直到完成,因为一旦保存此值更改)。

2) 现在您已经完全重新创建了所有实体,您需要将它们“连接”起来——因此所有关系都已正确设置。同样,为每个实体类型创建一些键数组,然后在循环中查看“A”中的每个关系,获取它指向的实体,使用转换表在“B”中找到对应的实体,然后设置'B' 中的值。

瞧!完成。您显然是添加是删除,您是否执行上述操作以反映 A - B 的更改。

同样,我不需要太担心 Mac 上的内存,所以不需要技巧来降低内存。我相信故障 ('refreshObject:mergeChanges:') 会对您有所帮助,但再也不必这样做(即使如此,可能只是尺寸较大的对象)。

于 2012-09-23T15:02:06.450 回答