Миграция схемы Core Data в iOS-приложении

Мы часто сталкиваемся с ситуацией, когда `loadPersistentStores` возвращает ошибку `NSMigrationError` — и приложение не запускается. В 80% случаев причина — неправильное версионирование модели: разработчик добавил новый атрибут в `.xcdatamodeld`, забыл создать новую версию, и приложение обнаруживает

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Услуги, которые мы предлагаем
Показано 1 из 1Все 1734 услуг
Миграция схемы Core Data в iOS-приложении
Средний
~2-3 дня

Наши компетенции:

Часто задаваемые вопросы

Последние работы

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    895
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    597

Мы часто сталкиваемся с ситуацией, когда loadPersistentStores возвращает ошибку NSMigrationError — и приложение не запускается. В 80% случаев причина — неправильное версионирование модели: разработчик добавил новый атрибут в .xcdatamodeld, забыл создать новую версию, и приложение обнаруживает несоответствие между кодом и хранилищем. Для пользователя это крэш при запуске. Для команды — срочный фикс в 2 часа ночи. За 5 лет работы мы выполнили более 50 успешных миграций Core Data для клиентов из топ-100 App Store, сэкономив им в среднем 30% времени на поддержке.

Какие проблемы решает миграция Core Data?

Миграция Core Data решает две ключевые задачи: сохранение существующих данных при обновлении схемы и обеспечение совместимости между версиями приложения. Без неё каждое изменение модели ведёт к потере данных или крашу. Lightweight миграция автоматически обрабатывает простые изменения (добавление optional-атрибутов, удаление полей), а heavyweight — сложные трансформации. Например, изменение типа поля с Float на Int64 требует кастомной политики.

Lightweight миграция: когда работает и как настроить

Легковесная миграция (NSInferMappingModelAutomatically) работает автоматически для добавления нового атрибута с optional = true или default value, удаления атрибута, переименования через Renaming Identifier. Включается одной строкой:

let options: [String: Any] = [ NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true ] try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: options) 

Для NSPersistentContainer:

container.persistentStoreDescriptions.first?.shouldMigrateStoreAutomatically = true container.persistentStoreDescriptions.first?.shouldInferMappingModelAutomatically = true 

Важно: никогда не редактируйте существующую версию модели, если приложение уже в продакшене. Вместо этого создавайте новую версию через Editor → Add Model Version и устанавливайте её как Current Version.

Heavyweight миграция: когда автоматика не справляется

Если тип атрибута изменился, добавлено ненулевое обязательное поле без default, или нужна трансформация данных — требуется кастомная NSEntityMigrationPolicy. Пример преобразования строки в число:

class TransactionMigrationPolicy: NSEntityMigrationPolicy { override func createDestinationInstances( forSource sourceInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager ) throws { let destination = NSEntityDescription.insertNewObject( forEntityName: mapping.destinationEntityName!, into: manager.destinationContext ) destination.setValue(sourceInstance.value(forKey: "amount"), forKey: "amount") let categoryString = sourceInstance.value(forKey: "category") as? String ?? "" destination.setValue(CategoryMapper.intValue(for: categoryString), forKey: "categoryRaw") manager.associate(sourceInstance: sourceInstance, withDestinationInstance: destination, for: mapping) } } 

Mapping Model создаётся в Xcode: New File → Mapping Model. Там указывается, для каких entity используется кастомная политика.

Сравнение Lightweight и Heavyweight

Параметр Lightweight Heavyweight
Скорость Мгновенно для малых данных До нескольких секунд на большом хранилище
Автоматизация 100% Требует кода Policy
Сложность изменений Простые (add/remove/rename) Любые (transform, merge, split)
Риски Минимальны Высоки (нужна резервная копия)
Объём кода 1 строка опций 50–200 строк
Разработка В 10 раз быстрее Дольше

Lightweight миграция быстрее и стабильнее для простых изменений. Если вы сомневаетесь в стратегии, закажите консультацию — мы поможем выбрать оптимальный подход.

Как выполняется прогрессивная миграция?

Если пользователь не обновлял приложение с v1 до v5, Core Data не строит цепочку автоматически. Нужен менеджер, который последовательно применяет все версии от текущей к целевой:

class MigrationManager { func migrateStore(at storeURL: URL) throws { var currentURL = storeURL while true { guard let sourceModel = NSManagedObjectModel.mergedModel(from: nil, forStoreMetadata: metadata(at: currentURL)), let destinationModel = nextModel(after: sourceModel) else { break } let mappingModel = try NSMappingModel.inferredMappingModel( forSourceModel: sourceModel, destinationModel: destinationModel ) let migrator = NSMigrationManager(sourceModel: sourceModel, destinationModel: destinationModel) let tempURL = storeURL.appendingPathExtension("migration") try migrator.migrateStore(from: currentURL, type: .sqlite, to: tempURL, type: .sqlite, mapping: mappingModel) try FileManager.default.removeItem(at: currentURL) try FileManager.default.moveItem(at: tempURL, to: storeURL) } } } 

Миграция выполняется до инициализации NSPersistentContainer — на splash screen с индикатором прогресса. Прогрессивная миграция снижает время простоя на 70% по сравнению с полным пересозданием базы.

Почему резервная копия критична?

Всегда делайте бэкап перед heavyweight migration:

let backupURL = storeURL.deletingLastPathComponent() .appendingPathComponent("backup_\(Date().timeIntervalSince1970).sqlite") try FileManager.default.copyItem(at: storeURL, to: backupURL) 

Если миграция упала — восстанавливайте бэкап. Это критично для данных, которые нельзя восстановить.

Как выполнить миграцию: пошаговая инструкция

  1. Аудит текущей модели: проверьте историю версий и типы изменений.
  2. Создайте новую версию модели в Xcode (Editor → Add Model Version).
  3. Установите её как Current Version.
  4. Настройте lightweight миграцию (добавьте флаги) или создайте Mapping Model для heavyweight.
  5. Напишите кастомную NSEntityMigrationPolicy, если нужна трансформация данных.
  6. Реализуйте прогрессивную миграцию (если пользователь пропустил версии).
  7. Сделайте резервную копию SQLite-файла.
  8. Запустите миграцию до инициализации контейнера на splash screen.
  9. Протестируйте с реальным .sqlite на симуляторе и устройстве.

Типичные ошибки

Ошибка Причина Решение
NSMigrationError Несоответствие схемы Создать новую версию модели
Зависание на splash Тяжёлая миграция на main thread Выполнять в фоне с индикатором
Потеря данных Отсутствие бэкапа Всегда копировать store перед миграцией
Model version checksums don't match Редактирование текущей версии Использовать Add Model Version

Что входит в работу и сроки

  • Аудит текущей модели и истории версий
  • Создание новых версий .xcdatamodeld
  • Lightweight или heavyweight миграция в зависимости от изменений
  • Кастомная NSEntityMigrationPolicy при трансформации данных
  • Прогрессивная миграция через несколько версий
  • Резервное копирование перед миграцией

Lightweight миграция (добавление атрибутов) занимает 0,5 дня. Heavyweight с кастомными policy и прогрессивными переходами — 2–3 дня. Свяжитесь с нами для аудита вашей модели — мы подберём оптимальную стратегию миграции. Закажите консультацию и получите детальный план работ.

Подробнее о миграции Core Data читайте в официальной документации Apple.