Migraciones de bases de datos en Swift (iOS/macOS)
El desarrollo de aplicaciones para iOS y macOS a menudo requiere trabajar con bases de datos locales. A medida que la aplicación evoluciona, la estructura de datos cambia inevitablemente: se añaden nuevos campos, se modifican tipos o se eliminan entidades obsoletas. Sin un mecanismo de migración adecuado, estos cambios pueden provocar la pérdida de datos del usuario o el bloqueo de la aplicación. En este artículo, exploraremos las principales herramientas y enfoques para realizar migraciones de bases de datos en Swift, y proporcionaremos ejemplos prácticos para soluciones populares.
¿Por qué son importantes las migraciones?
Las migraciones de bases de datos garantizan:
- Preservación de datos — los registros del usuario no se pierden al actualizar el esquema.
- Compatibilidad hacia atrás — la aplicación sigue funcionando con versiones antiguas de los datos.
- Flexibilidad de desarrollo — la capacidad de cambiar iterativamente el modelo de datos sin intervención manual.
Herramientas principales para migraciones en Swift
1. Core Data + NSPersistentContainer
El framework integrado de Apple proporciona migraciones automáticas y ligeras. Para cambios complejos, se utiliza el versionado manual del modelo.
// Configuración del contenedor con soporte de migracioneslet container = NSPersistentContainer(name: "MyAppModel")container.persistentStoreDescriptions.first?.shouldMigrateStoreAutomatically = truecontainer.persistentStoreDescriptions.first?.shouldInferMappingModelAutomatically = true
container.loadPersistentStores { description, error in if let error = error { fatalError("Error al cargar el almacén: \\(error)") }}Para la migración manual, se crean versiones del modelo (.xcdatamodeld) y NSMappingModel:
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 — controlador SQLite moderno
GRDB.swift ofrece un mecanismo de migración flexible basado en el registro de pasos. Las migraciones se ejecutan de forma secuencial y atómica.
import GRDB
var migrator = DatabaseMigrator()
// Registro de la primera migraciónmigrator.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() }}
// Registro de la segunda migración (adición de campo)migrator.registerMigration("v2_add_age") { db in try db.alter(table: "users") { t in t.add(column: "age", .integer).defaults(to: 0) }}
// Aplicación de migraciones al iniciar la aplicaciónlet dbQueue = try DatabaseQueue(path: "/path/to/database.sqlite")try migrator.migrate(dbQueue)Ventajas de GRDB.swift: consultas tipadas, soporte de transacciones, reversión sencilla de migraciones.
3. Realm Swift (ahora Atlas Device SDK)
Realm maneja automáticamente la mayoría de las migraciones, pero para cambios complejos se requiere una actualización explícita del esquema.
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"] ?? "")" } También en la biblioteca
Parseo de HTML en Node.js: revisión de las mejores bibliotecas y herramientas
Trabajo con S3 y almacenamiento en la nube en C++: biblioteca aws-sdk-cpp
Internacionalización (i18n) en TypeScript: guía completa