Core Data vs SwiftData para persistencia — ¿cómo eliges en una app nueva?
Core Data tiene una década de cicatrices en producción; SwiftData tiene una fracción del código — elegir entre ambos para una app nueva es una decisión arquitectónica real.
APRENDE HACIENDOPon a prueba tu intuición3 pasos
Core Data vs SwiftData para persistencia — ¿cómo eliges en una app nueva?
Usa los ejemplos y la explicación de la lección para comprobar tu idea.
Reflexión personal. No se envía a ningún servicio de IA.#Dos frameworks, un mismo trabajo de fondo
Tanto Core Data como SwiftData existen para persistir objetos modelo de Swift en disco y consultarlos de vuelta con eficiencia, con seguimiento de cambios y (opcionalmente) sincronización con CloudKit. Core Data existe desde iOS 3 en 2009; SwiftData llegó en la WWDC 2023 para iOS 17+, construido como una capa nativa de Swift sobre una infraestructura de persistencia con profunda herencia de Core Data. Un entrevistador que te pide elegir entre ambos quiere un marco de decisión real, no una respuesta refleja de "SwiftData es más nuevo, así que es mejor."
#Core Data, en la práctica
Un stack de Core Data gira en torno a un archivo .xcdatamodeld (un editor visual de modelos) que genera subclases de NSManagedObject, un NSPersistentContainer que posee el store y los contextos, un NSManagedObjectContext a través del cual haces fetch y guardas, y NSFetchRequest con NSPredicate/NSSortDescriptor para consultar. NSFetchedResultsController impulsa las actualizaciones de UITableView/UICollectionView de forma eficiente en UIKit. Soporta migraciones automáticas ligeras para cambios de esquema aditivos y modelos de mapeo completamente personalizados para los complejos, y NSPersistentCloudKitContainer añade sincronización con CloudKit con más control del que SwiftData expone actualmente. El costo es boilerplate real — un archivo de modelo separado, clases generadas, y una superficie de API arraigada en el dinamismo de Objective-C (las instancias de NSManagedObject entran y salen de memoria mediante "faulting", lo cual es poderoso pero a veces sorprendente de depurar).
#SwiftData, en la práctica
@Model convierte una class de Swift normal en una entidad persistida directamente en el código — sin archivo de modelo separado, sin subclase generada que mantener sincronizada. @Query es un property wrapper que hace fetch directamente hacia una vista de SwiftUI y la mantiene actualizada reactivamente a medida que cambia el store, reemplazando NSFetchedResultsController y sus callbacks de delegado con unas pocas líneas. ModelContainer y ModelContext cumplen los roles de NSPersistentContainer y NSManagedObjectContext. Las migraciones se expresan mediante VersionedSchema y un SchemaMigrationPlan. Por debajo, SwiftData está construido sobre la misma herencia de persistencia que Core Data — no es un motor de base de datos desde cero —, lo cual es parte de por qué ambos pueden coexistir o migrar de uno a otro de forma más realista que cambiar a algo completamente distinto.
#Cómo elegir en la práctica
El target de despliegue es la restricción dura: cualquier cosa por debajo de iOS 17 descarta a SwiftData por completo. Por encima de ese piso, una app de SwiftUI construida desde cero se beneficia del boilerplate mucho menor de SwiftData y de la reactividad nativa de @Query — menos código haciendo el mismo trabajo para datos directos, con una entidad por pantalla. Recurre a Core Data en cambio cuando necesites capacidades que SwiftData todavía no expone del todo — propiedades fetched, control fino de NSFetchedResultsController para una lista en UIKit, modelos de mapeo para migraciones personalizadas complejas, o configuraciones de store que Core Data ha soportado durante más de una década. Y si ya existe un modelo grande y funcional de Core Data en producción, ese es un argumento fuerte para dejarlo tal cual en lugar de reescribirlo por capricho — la madurez de SwiftData, sobre todo en migraciones complejas y expresividad de predicados, todavía está poniéndose al día en iOS 17/18.
#La brecha de los predicados
#Predicate en SwiftData es un closure de Swift comprobado en tiempo de compilación, lo cual es genuinamente más seguro que los format strings débilmente tipados de NSPredicate — un error tipográfico en un key path es un error del compilador en lugar de un crash en tiempo de ejecución. Pero a partir de iOS 17/18 soporta un conjunto más estrecho de expresiones: algunas operaciones de strings, ciertas subconsultas, y algunas operaciones sobre colecciones que NSPredicate maneja rutinariamente todavía no compilan en #Predicate. Verifica los patrones de consulta específicos que necesita una funcionalidad antes de comprometerte con SwiftData para trabajo intensivo en datos.
#En código
// Core Data: la entidad se define en el .xcdatamodeld, subclase de NSManagedObject generada.extension Task {@NSManaged var title: String@NSManaged var isDone: Bool@NSManaged var createdAt: Date}func fetchOpenTasks(context: NSManagedObjectContext) throws -> [Task] {let request = Task.fetchRequest()request.predicate = NSPredicate(format: "isDone == NO")request.sortDescriptors = [NSSortDescriptor(keyPath: \Task.createdAt, ascending: false)]return try context.fetch(request) as! [Task]}
// SwiftData: el modelo ES el tipo de Swift, sin archivo de modelo separado.import SwiftData@Modelfinal class Task {var title: Stringvar isDone: Boolvar createdAt: Dateinit(title: String, isDone: Bool = false, createdAt: Date = .now) {self.title = titleself.isDone = isDoneself.createdAt = createdAt}}struct TaskListView: View {@Query(filter: #Predicate<Task> { !$0.isDone },sort: \Task.createdAt, order: .reverse)private var openTasks: [Task]@Environment(\.modelContext) private var contextvar body: some View {List(openTasks) { task inText(task.title)}.toolbar {Button("Agregar") {context.insert(Task(title: "Nueva tarea"))}}}}
#Decidiendo
🧠 Check your understanding
0/3 · 0/3 answered1. ¿Cuál es la restricción principal que te obligaría a usar Core Data en lugar de SwiftData en una app nueva?
2. En SwiftData, ¿qué obtiene una lista reactiva y en vivo de objetos modelo directamente en una vista de SwiftUI?
3. ¿En qué se diferencia #Predicate de SwiftData respecto a NSPredicate?