Migrations de bases de données en Swift : outils et pratiques pour iOS/macOS

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Migrations de bases de données en Swift (iOS/macOS)



Le développement d'applications pour iOS et macOS nécessite souvent de travailler avec des bases de données locales. Au fur et à mesure que l'application évolue, la structure des données change inévitablement : de nouveaux champs sont ajoutés, les types sont modifiés ou des entités obsolètes sont supprimées. Sans un mécanisme de migration approprié, ces changements peuvent entraîner une perte de données utilisateur ou un plantage de l'application. Dans cet article, nous examinerons les principaux outils et approches pour effectuer des migrations de bases de données en Swift, et nous fournirons des exemples pratiques pour les solutions populaires.



Pourquoi les migrations sont-elles importantes ?

Les migrations de bases de données assurent :

  • La préservation des données — les enregistrements utilisateur ne sont pas perdus lors de la mise à jour du schéma.
  • La rétrocompatibilité — l'application continue de fonctionner sur les anciennes versions des données.
  • La flexibilité du développement — la possibilité de modifier itérativement le modèle de données sans intervention manuelle.


Principaux outils pour les migrations en Swift



1. Core Data + NSPersistentContainer

Le framework intégré d'Apple fournit des migrations automatiques et légères. Pour les modifications complexes, un versionnement manuel du modèle est utilisé.

// Configuration du conteneur avec prise en charge des migrationslet container = NSPersistentContainer(name: "MyAppModel")container.persistentStoreDescriptions.first?.shouldMigrateStoreAutomatically = truecontainer.persistentStoreDescriptions.first?.shouldInferMappingModelAutomatically = true

container.loadPersistentStores { description, error in if let error = error { fatalError("Failed to load store: \\(error)") }}

Pour la migration manuelle, des versions du modèle (.xcdatamodeld) et NSMappingModel sont créées :

let sourceModel = NSManagedObjectModel(contentsOf: sourceURL)!let destinationModel = NSManagedObjectModel(contentsOf: destinationURL)!let mappingModel = NSMappingModel(from: [sourceModel, destinationModel], forSourceModel: sourceModel, destinationModel: destinationModel)

let manager = NSMigrationManager(sourceModel: sourceModel, destinationModel: destinationModel)try? manager.migrateStore(from: sourceURL, sourceType: NSSQLiteStoreType, options: nil, with: mappingModel, toDestinationURL: destinationURL, destinationType: NSSQLiteStoreType, destinationOptions: nil)


2. GRDB.swift — pilote SQLite moderne

GRDB.swift offre un mécanisme de migration flexible basé sur l'enregistrement d'étapes. Les migrations sont exécutées séquentiellement et atomiquement.

import GRDB

var migrator = DatabaseMigrator()

// Enregistrement de la première migrationmigrator.registerMigration("v1_create_users") { db in try db.create(table: "users") { t in t.autoIncrementedPrimaryKey("id") t.column("name", .text).notNull() t.column("email", .text).unique() }}

// Enregistrement de la deuxième migration (ajout d'un champ)migrator.registerMigration("v2_add_age") { db in try db.alter(table: "users") { t in t.add(column: "age", .integer).defaults(to: 0) }}

// Application des migrations au démarrage de l'applicationlet dbQueue = try DatabaseQueue(path: "/path/to/database.sqlite")try migrator.migrate(dbQueue)

Avantages de GRDB.swift : requêtes typées, prise en charge des transactions, annulation simple des migrations.



3. Realm Swift (maintenant Atlas Device SDK)

Realm gère automatiquement la plupart des migrations, mais pour les modifications complexes, une mise à jour explicite du schéma est nécessaire.

import RealmSwift

let config = Realm.Configuration( schemaVersion: 2, migrationBlock: { migration, oldSchemaVersion in if oldSchemaVersion < 1 { migration.enumerateObjects(ofType: "User") { oldObject, newObject in newObject?["fullName"] = "\\(oldObject!["firstName"] ?? "") \\(oldObject!["lastName"] ?? "")" }

Recommendations