Ответ
Да, приходилось. Кастомные (тяжелые) миграции в Core Data необходимы, когда автоматическая лёгкая миграция (lightweight migration) невозможна. Это происходит при сложных изменениях схемы данных, таких как:
- Разделение одного атрибута на несколько.
- Объединение нескольких атрибутов в один.
- Нелинейные преобразования данных (например, изменение формата даты или вычисление нового значения на основе старых).
- Изменение иерархии сущностей (entity inheritance).
Процесс и пример:
Миграция выполняется с помощью NSEntityMigrationPolicy. Необходимо создать Mapping Model (.xcmappingmodel) и указать в нём кастомный класс политики.
Пример политики миграции для преобразования полного имени (fullName) в отдельные атрибуты firstName и lastName:
import CoreData
class SplitNameMigrationPolicy: NSEntityMigrationPolicy {
@objc func transformFullName(forFullName: NSString?) -> [String: String]? {
// Логика разделения строки
guard let fullName = forFullName as String? else { return nil }
let components = fullName.split(separator: " ").map(String.init)
let firstName = components.first ?? ""
let lastName = components.dropFirst().joined(separator: " ") // На случай двойных фамилий
return ["firstName": firstName, "lastName": lastName]
}
}
В Mapping Model для атрибута firstName в качестве Value Expression указывается: FUNCTION($entityPolicy, "transformFullNameForFullName:", $source.fullName)["firstName"].
Критически важные практики:
- Тестирование на копии реальной базы данных перед выпуском обновления приложения.
- Поэтапные миграции для очень больших изменений (версия 1 -> 2 -> 3).
- Обеспечение обратной совместимости и обработка
nil-значений. - Информирование пользователя о процессе, так как миграция может занять время.
Ответ 18+ 🔞
Ох, блядь, вспомнил — да, приходилось, сука, вляпываться в это болото. Кастомные, они же тяжёлые, миграции в Core Data — это когда автоматическая лёгкая миграция (lightweight migration) просто пиздец как не катит. Такое случается, когда у тебя в схеме данных происходят хуёво-сложные изменения, типа:
- Один атрибут надо распидорасить на несколько.
- Несколько атрибутов склеить в один, как говно с лопатой.
- Данные нужно преобразовать по какой-то ёбаной нелинейной логике — скажем, поменять формат даты или высрать новое значение из старых.
- Ковыряешься в иерархии сущностей (entity inheritance) — тут вообще пиздец начинается.
Как это, блядь, делается и пример:
Всё вертится вокруг NSEntityMigrationPolicy. Нужно создать Mapping Model (этот файлик .xcmappingmodel) и в нём указать свой кастомный класс.
Вот, например, политика, которая из одного поля fullName делает два отдельных — firstName и lastName:
import CoreData
class SplitNameMigrationPolicy: NSEntityMigrationPolicy {
@objc func transformFullName(forFullName: NSString?) -> [String: String]? {
// Логика разделения строки
guard let fullName = forFullName as String? else { return nil }
let components = fullName.split(separator: " ").map(String.init)
let firstName = components.first ?? ""
let lastName = components.dropFirst().joined(separator: " ") // На случай двойных фамилий
return ["firstName": firstName, "lastName": lastName]
}
}
А потом в этом Mapping Model'е для атрибута firstName в поле Value Expression пишешь какую-то хуйню вида: FUNCTION($entityPolicy, "transformFullNameForFullName:", $source.fullName)["firstName"]. В рот меня чих-пых, выглядит страшно, но работает.
А теперь, сука, главное, что нужно запомнить, чтобы не обосраться:
- Тестируй на копии реальной базы, ёпта! Не вздумай выпускать обновление, не проверив на живых данных — будет тебе овердохуища боли.
- Если изменения пиздец какие огромные, делай поэтапные миграции (версия 1 -> 2 -> 3). Не пытайся прыгнуть с первого этажа на десятый.
- Обратная совместимость и обработка
nil— святое. Твой код не должен разъебаться, если в старых данных какая-то хуйня. - Предупреди пользователя! Эта штука может ебашить долго. Пусть знает, что приложение не зависло, а просто занимается важным делом — перекладыванием говна из одной кучи в другую.