Я понял, что Apple намекает в их документации . Это на самом деле очень легко, но долгий путь, прежде чем он станет очевидным. Я проиллюстрирую объяснение на примере. Исходная ситуация такова:
Модель данных версии 1
![enter image description here](https://i.stack.imgur.com/T6i3n.png)
Это модель, которую вы получаете, когда создаете проект с помощью шаблона «приложение на основе навигации с основным хранилищем данных». Я скомпилировал его и сделал несколько сложных ударов с помощью цикла for, чтобы создать около 2 тыс. Записей с разными значениями. Там мы идем 2000 событий со значением NSDate.
Теперь мы добавим вторую версию модели данных, которая выглядит следующим образом:
![enter image description here](https://i.stack.imgur.com/T14rf.png)
Модель данных версии 2
Разница в том, что сущность Event исчезла, и у нас есть две новые. Тот, который хранит метку времени как double
, а второй, который должен хранить дату как NSString
.
Цель состоит в том, чтобы передать все Версия 1 События двум новым объектам и преобразовать значения в процессе миграции. Это приводит к удвоению значений каждого из них как отдельного типа в отдельном объекте.
Для миграции мы выбираем миграцию вручную, и это мы делаем с моделями сопоставления. Это также первая часть ответа на ваш вопрос. Мы сделаем миграцию в два этапа, потому что миграция записей 2k занимает много времени, и мы хотим, чтобы объем памяти оставался низким.
Вы могли бы даже пойти дальше и разделить эти модели отображения дальше, чтобы перенести только диапазоны сущностей. Скажем, у нас есть миллион записей, это может привести к краху всего процесса. Можно сузить выбранные объекты с помощью предиката Filter .
Вернуться к нашим двум картографическим моделям.
Мы создаем первую модель отображения следующим образом:
1. Новый файл -> Ресурс -> Модель отображения
![enter image description here](https://i.stack.imgur.com/4eV4U.png)
2. Выберите имя, я выбрал StepOne
3. Установить исходную и целевую модель данных
![enter image description here](https://i.stack.imgur.com/hWddI.png)
Модель отображения Шаг первый
![enter image description here](https://i.stack.imgur.com/eKXB3.png)
![enter image description here](https://i.stack.imgur.com/uM34V.png)
![enter image description here](https://i.stack.imgur.com/GDVnC.png)
Многопроходная миграция не требует настраиваемых политик миграции сущностей, однако мы сделаем это, чтобы получить немного больше подробностей для этого примера. Таким образом, мы добавляем пользовательскую политику к объекту. Это всегда подкласс NSEntityMigrationPolicy
.
![enter image description here](https://i.stack.imgur.com/6fZmi.png)
Этот класс политики реализует несколько методов, позволяющих осуществить нашу миграцию. Однако в этом случае все просто, поэтому нам придется реализовать только один метод: createDestinationInstancesForSourceInstance:entityMapping:manager:error:
.
Реализация будет выглядеть так:
StepOneEntityMigrationPolicy.m
#import "StepOneEntityMigrationPolicy.h"
@implementation StepOneEntityMigrationPolicy
- (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)sInstance
entityMapping:(NSEntityMapping *)mapping
manager:(NSMigrationManager *)manager
error:(NSError **)error
{
// Create a new object for the model context
NSManagedObject *newObject =
[NSEntityDescription insertNewObjectForEntityForName:[mapping destinationEntityName]
inManagedObjectContext:[manager destinationContext]];
// do our transfer of nsdate to nsstring
NSDate *date = [sInstance valueForKey:@"timeStamp"];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
// set the value for our new object
[newObject setValue:[dateFormatter stringFromDate:date] forKey:@"printedDate"];
[dateFormatter release];
// do the coupling of old and new
[manager associateSourceInstance:sInstance withDestinationInstance:newObject forEntityMapping:mapping];
return YES;
}
Последний шаг: сама миграция
Я пропущу часть для настройки второй модели сопоставления, которая почти идентична, просто timeIntervalSince1970, используемый для преобразования NSDate в double.
Наконец, нам нужно запустить миграцию. Я пока пропущу шаблонный код. Если вам это нужно, я выложу здесь. Его можно найти по адресу Настройка процесса миграции Это всего лишь слияние первых двух примеров кода. Третья и последняя часть будут изменены следующим образом: Вместо использования метода класса NSMappingModel
class mappingModelFromBundles:forSourceModel:destinationModel:
мы будем использовать initWithContentsOfURL:
потому что метод класса вернет только одну, может быть, первую найденную модель отображения в комплекте.
Теперь у нас есть две модели отображения, которые можно использовать на каждом проходе цикла, и отправить метод migrate в менеджер миграции. Вот и все.
NSArray *mappingModelNames = [NSArray arrayWithObjects:@"StepOne", @"StepTwo", nil];
NSDictionary *sourceStoreOptions = nil;
NSURL *destinationStoreURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreDataMigrationNew.sqlite"];
NSString *destinationStoreType = NSSQLiteStoreType;
NSDictionary *destinationStoreOptions = nil;
for (NSString *mappingModelName in mappingModelNames) {
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:mappingModelName withExtension:@"cdm"];
NSMappingModel *mappingModel = [[NSMappingModel alloc] initWithContentsOfURL:fileURL];
BOOL ok = [migrationManager migrateStoreFromURL:sourceStoreURL
type:sourceStoreType
options:sourceStoreOptions
withMappingModel:mappingModel
toDestinationURL:destinationStoreURL
destinationType:destinationStoreType
destinationOptions:destinationStoreOptions
error:&error2];
[mappingModel release];
}
Примечания
Модель отображения заканчивается на cdm
в связке.
Должно быть указано хранилище назначения, и оно не должно быть хранилищем источника. После успешной миграции вы можете удалить старую и переименовать новую.
Я сделал некоторые изменения в модели данных после создания моделей отображения, это привело к некоторым ошибкам совместимости, которые я мог исправить только путем воссоздания моделей отображения.