1

コアデータ標準の移行に関するこちらのチュートリアルに従いました。

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

そして、複数のパスでそれを行うことについてここに1つ:

複数のパスを使用した Core Data Migration の例または説明は?

結果のコードは次のとおりです。

- (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

私が数年前に解決した問題は、基本的にあるリポジトリからサブツリーを取り出して別のリポジトリに複製することでした。私はこれを Mac で行っていたので、メモリは問題ではありませんでしたが、Core Data Programming Guide の「Reducing Memory Overhead」に従って、適切なフォールトとメモリの削減により、これを機能させることができるはずです。

次の解決策は、MOM がそれほど異なるわけではないという前提に基づいています。既存のコンテキストを「A」、新しいコンテキストを「B」という用語を紹介しましょう。

1) 最初のステップは、A のすべてのオブジェクトを B に複製することです。クラスが同じままである場合は、問題ありません。これは、すべてのオブジェクトについて、エンティティからのすべての値のリストが必要であることを意味します。各エンティティ タイプの属性キーの配列であるキーを使用することをお勧めします。これにより、コーディングが容易になります (可能であれば)。それ以外の場合は、実際に MOM からキーを取得できます。これは、古いコードで行ったことです。

ここで重要なステップ - 翻訳辞書を作成する必要があります (おそらく 2 つ必要です - 私は作成しました)。A のすべてのエンティティに対して、対応する 'B' のエンティティを知っている必要があります。「objectID」プロパティを使用できます (ただし、B の場合は、この値の変更を保存すると終了するまで保存しないでください)。

2) すべてのエンティティを完全に再作成したので、それらを「接続」する必要があります。これにより、すべての関係が適切に設定されます。繰り返しますが、エンティティ タイプごとにいくつかのキーの配列を作成し、ループで「A」の各関係を調べ、それが指すエンティティを取得し、変換テーブルを使用して「B」の対応するものを見つけ、設定します。 「B」の値。

出来上がり!終わった。A - B からの変更をミラーリングするために上記を実行する場合、明らかに追加と削除を行います。

繰り返しになりますが、Mac のメモリについてそれほど心配する必要はなかったので、メモリを抑えるためのトリックは必要ありませんでした。フォルト ('refreshObject:mergeChanges:') が役立つと思いますが、これを行う必要はありませんでした (それでも、おそらくサイズが大きいオブジェクトだけです)。

于 2012-09-23T15:02:06.450 に答える
0

このチュートリアルにも従ったことを覚えています。

実際、これは正しい方法ではないことがわかりました。ところで、そのチュートリアルの最後のコメントを読んで、言及された行を削除しようとしましたか? 多分それはあなたの場合にそれを修正しますか?

とにかく、私の場合、(このチュートリアルに従った後、変更が役に立たなかった後) はるかに簡単な方法があることに気付きました。

あなたの場合、私にはわかりませんが、この小さな変更で修正されない場合は、別の参照を実際に探します-これは実際には正しい方法ではなく、間違った方向に導くためです。私が難しい方法を見つけたので、Apple のコア データ移行手順の背後にあるロジックを使用する代わりに、すべてそのものを使用します。

于 2012-09-23T14:45:57.903 に答える