Introducción a Core Data
¿Qué es Core Data?¶
Core Data es el principal framework de persistencia de iOS. Nos proporciona un mecanismo para poder almacenar de forma persistente los objetos de nuestra aplicación y luego recuperarlos. Es capaz de guardar automáticamente un grafo entero de objetos con las relaciones (uno a uno, uno a muchos, muchos a muchos) que hay entre ellos. Si bien es un API complejo y tiene una curva de aprendizaje pronunciada, para cualquier aplicación medianamente grande usar Core Data nos va a resultar mucho más sencillo que implementar nosotros la persistencia de manera manual con, digamos, SQLite.
Core Data se puede considerar en cierto modo como un ORM (object relational mapper). A los desarrolladores que hayan usado un ORM en cualquier lenguaje les va a resultar familiar si no el API sí al menos las ideas básicas y la filosofía de trabajo. Aún más, ciertos términos usados en Core Data (objetos gestionados, contexto, ...) son típicos también de otros ORM como por ejemplo JPA en Java.
Siendo puristas, Core Data no es un ORM estrictamente hablando, ya que su objetivo no es la persistencia únicamente en bases de datos relacionales. En principio el backend de persistencia podría ser cualquiera. Con la implementación actual Core Data admite como única BD relacional para persistencia SQLite, y también puede almacenar datos en memoria y en XML (esto último solo en OSX).
El stack de Core Data¶
El stack de Core Data usa un cierto número de clases con una terminología que al principio puede resultar un poco confusa o complicada. La tarea de almacenar de forma persistente un grafo de objetos en realidad es complicada, así que en parte por eso lo es la infraestructura necesaria. Vamos a resumir aquí brevemente el papel de cada componente del stack
Por supuesto, para poder almacenar información de forma persistente lo primero es disponer de un medio de almacenamiento persistente (una base de datos relacional, un fichero XML, un archivo JSON,…). El NSPersistentStore
es la clase que se ocupa de gestionar este almacenamiento persistente. Core Data nos proporciona dos implementaciones de almacenamiento "persistente" en iOS: la BD relacional SQLite, que ya conocemos, y el almacenamiento en memoria. También podemos escribir nuestras propias implementaciones de NSPersistentStore
.
Es evidente que el almacenamiento en memoria no es precisamente persistente, pero va a ser muy rápido y es apropiado para manejar datos de solo lectura o que puedan ser fácilmente re-creados.
El NSPersistentStoreCoordinator
podría considerarse como el núcleo de Core Data. Es la clase responsable de gestionar la persistencia y por eso tiene que interactuar con el NSPersistentStore
. No obstante, por muy importante que sea su papel de modo interno nuestro código no va a interactuar apenas con esta clase, salvo en su inicialización. Para poder hacer su trabajo, el NSPersistentStoreCoordinator
necesita de un modelo de datos, o NSManagedObjectModel
. Este modelo, que es similar a lo que sería un modelo E-R en una base de datos relacional, define las “clases” que componen nuestro modelo del dominio, especificando sus atributos y las relaciones entre clases. Como veremos, en el proyecto de Xcode un modelo de datos se representa con un archivo .xcdatamodeld
. El NSManagedObjectModel
sería como la versión compilada y binaria de este archivo. De nuevo solo vamos a usar directamente esta clase en nuestro código en la parte de inicialización (aunque por supuesto crear y editar el archivo .xcdatamodeld
nos va a llevar bastante tiempo para cualquier modelo no trivial).
Llegamos ya a las clases con las que nuestro código va a interactuar más habitualmente:
NSManagedObjectContext
es el “contexto de persistencia”. Este contexto es un grafo de objetos, relacionados entre sí, y cuyo ciclo de vida está gestionado por Core Data (de ahí la terminología de managed objects). Esto significa que por ejemplo no creamos los objetos persistentes como habitualmente (con el inicializador) sino que le debemos pedir alNSManagedObjectContext
que los cree por nosotros. Cada vez que necesitemos recuperar un objeto del almacenamiento persistente o guardarlo allí, también tendremos que pedírselo al contexto. Así que no es difícil ver por qué va esta clase va a aparecer tanto en nuestro código.- Como hemos dicho, los objetos gestionados por el contexto de persistencia son los que representan nuestro modelo del dominio. Estos objetos son de la clase
NSManagedObject
o de clases descendientes de ella. Conforme vayamos realizando operaciones en la aplicación iremos llenándolos de datos, relacionándolos entre sí, guardándolos, buscándolos, etc.
Gestionar tantas clases puede ser complicado, por lo que desde hace unas cuantas versiones de Core Data tenemos disponible el NSPersistentContainer
, que permite crear todo el stack de manera sencilla, como veremos en el siguiente apartado.
Finalmente, si para buscar datos en una base de datos relacional se usa SQL, para recuperar objetos del almacenamiento persistente en Core Data usaremos NSFetchRequest
. Al igual que en SQL podemos ejecutar consultas especificando las condiciones que deben cumplir los objetos a recuperar.