基本的なプロセスは次のとおりです。
データモデルのバージョン管理されたコピーを作成します。(モデルを選択し、[エディター]-> [モデルバージョンの追加]を選択します)
データモデルの新しいコピーに変更を加えます
新しいデータモデルのコピーを現在のバージョンとしてマークします。(最上位のxcdatamodelアイテムをクリックし、ファイルインスペクターで、[バージョン管理されたデータモデル]セクションの[現在]エントリを、手順1で作成した新しいデータモデルに設定します。
モデルオブジェクトを更新して、RecipeIngredientエンティティを追加します。また、RecipeエンティティとIngredientエンティティの成分とレシピの関係を、ステップ2でRecipeIngredientエンティティに対して作成した新しい関係に置き換えます。(両方のエンティティにこの関係が追加されます。私はrecipeIngredientsと呼びました)明らかに、古いコードで材料からレシピへの関係を作成する場合は常に、RecipeIngredientオブジェクトを作成する必要があります。しかし、それはこの回答の範囲を超えています。
モデル間に新しいマッピングを追加します([ファイル]->[新しいファイル...]->([コアデータ]セクション)-> [マッピングモデル]。これにより、いくつかのマッピングが自動生成されます。RecipeToRecipe、IngredientToIngredient、およびRecipeIngredient。
RecipeIngredientマッピングを削除します。また、RecipeToRecipeおよびIngredientToRecipe(またはステップ2でそれらを呼び出したもの)に対して提供されるrecipeIngredientリレーションマッピングを削除します。
RecipeToRecipeマッピングをドラッグして、マッピングルールのリストの最後に配置します。(これは、レシピを移行するときに材料をリンクできるように、レシピの前に材料が確実に移行されるようにするために重要です。)移行は移行ルールリストの順序で行われます。
RecipeToRecipeマッピング「DDCDRecipeMigrationPolicy」のカスタムポリシーを設定します(これにより、Recipesオブジェクトの自動移行がオーバーライドされ、マッピングロジックを実行できるフックが提供されます。
レシピのNSEntityMigrationPolicyをサブクラス化してcreateDestinationInstancesForSourceInstanceをオーバーライドすることにより、DDCDRecipeMigrationPolicyを作成します(以下のコードを参照)。これは、レシピごとに1回呼び出されます。これにより、Recipeオブジェクトと、それをIngredientにリンクする関連するRecipeIngredientオブジェクトを作成できます。手順5でXcodeが自動作成したマッピングルールによって、Ingredientを自動移行します。
永続オブジェクトストア(おそらくAppDelegate)を作成する場合は常に、データモデルを自動移行するようにユーザーディクショナリを設定してください。
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, nil]
error:&error])
{
}
レシピのサブクラスNSEntityMigrationPolicy
#import <CoreData/CoreData.h>
@interface DDCDRecipeMigrationPolicy : NSEntityMigrationPolicy
@end
* DDCDRecipeMigrationPolicy.mのcreateDestinationInstancesForSourceInstanceをオーバーライドします*
- (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)sInstance entityMapping:(NSEntityMapping *)mapping manager:(NSMigrationManager *)manager error:(NSError **)error
{
NSLog(@"createDestinationInstancesForSourceInstance : %@", sInstance.entity.name);
//We have to create the recipe since we overrode this method.
//It's called once for each Recipe.
NSManagedObject *newRecipe = [NSEntityDescription insertNewObjectForEntityForName:@"Recipe" inManagedObjectContext:[manager destinationContext]];
[newRecipe setValue:[sInstance valueForKey:@"name"] forKey:@"name"];
[newRecipe setValue:[sInstance valueForKey:@"overview"] forKey:@"overview"];
[newRecipe setValue:[sInstance valueForKey:@"instructions"] forKey:@"instructions"];
for (NSManagedObject *oldIngredient in (NSSet *) [sInstance valueForKey:@"ingredients"])
{
NSFetchRequest *fetchByIngredientName = [NSFetchRequest fetchRequestWithEntityName:@"Ingredient"];
fetchByIngredientName.predicate = [NSPredicate predicateWithFormat:@"name = %@",[oldIngredient valueForKey:@"name"]];
//Find the Ingredient in the new Datamodel. NOTE!!! This only works if this is the second entity migrated.
NSArray *newIngredientArray = [[manager destinationContext] executeFetchRequest:fetchByIngredientName error:error];
if (newIngredientArray.count == 1)
{
//Create an intersection record.
NSManagedObject *newIngredient = [newIngredientArray objectAtIndex:0];
NSManagedObject *newRecipeIngredient = [NSEntityDescription insertNewObjectForEntityForName:@"RecipeIngredient" inManagedObjectContext:[manager destinationContext]];
[newRecipeIngredient setValue:newIngredient forKey:@"ingredient"];
[newRecipeIngredient setValue:newRecipe forKey:@"recipe"];
NSLog(@"Adding migrated Ingredient : %@ to New Recipe %@", [newIngredient valueForKey:@"name"], [newRecipe valueForKey:@"name"]);
}
}
return YES;
}
XcodeとサンプルXcodeプロジェクトのセットアップの写真を投稿しますが、スタックオーバーフローに関するレピュテーションポイントがまだないようです...そのため、許可されません。これもブログに投稿します。bingosabi.wordpress.com/。
また、Xcode Core Dataモデルのマッピングは少し不安定であり、「クリーン」で優れたXcodeレスター、シミュレーターバウンス、または上記のすべてが機能する必要がある場合があることにも注意してください。