¡Atención! Este sitio utiliza cookies.
Si no cambias la configuración de tu navegador, aceptas su uso.

Semillas de Cacao: Core Data – Introducción

Si estás desarrollando una app para iPhone o iPad y pensando en almacenar datos en ella, posiblemente hayas sopesado varias opciones, de entre ellas, utilizar una base de datos. En este caso, posiblemente hayas oído hablar de Core Data. Y posiblemente también te haya entrado un escalofrío.

coredata

En este artículo se abordarán los conceptos básicos para conocer todas las entidades que conforman Core Data, comprender de qué manera funcionan internamente, y cómo queremos usarlas en un primer contacto. El framework es enorme, complejo y requiere de un nivel medio de conocimientos en Cocoa antes de abordarlo; eso sí, es increíblemente potente. Una vez lo pruebes no querrás usar otra cosa.

Existen varios libros, artículos, tutoriales e incluso la documentación de Apple, así que por recursos que no quede. En esta introducción nos centraremos en conocer el framework desde una perspectiva sencilla y perderle el miedo para, posteriormente, crear nuestra primera app con una base de datos. ¿Empezamos?

Lo primero, ¿qué es Core Data?

Esta es la primera pregunta que me asaltó la primera vez que oí hablar de esto porque, ya de entrada, sonaba complicado. El hecho de manejar una base de datos me parecía programación de 2º Dan, y cuando empiezas a trastear con Objective-C y UIKit la primera vez, no es que eso sea lo que más te apetece. Lo que me hizo perder el miedo a esta herramienta fue, sobretodo, conocerla por encima y saber qué es, qué no es, y por qué tenía que usarla en lugar de otra.

Lo primero, Core Data no es un Sistema Gestor de bases de datos en sí mismo, ni un sistema de mapping relacional, es mucho más. Core Data es un entorno de herramientas diseñado por Apple para hacernos la vida más fácil en tareas como el guardado, la eliminación, el propio modelado de los objetos, y hasta la sincronización de la información con un coste de líneas de código (y de dolores de cabeza) muy bajo. Deja de soñar con archivos de texto, JSON, diccionarios, etc, y comienza a drogarte con Core Data, que es más barato.

¿Por qué Core Data?

Porque, si bien tiene una curva de aprendizaje empinada, una vez entendido su funcionamiento esencial te da una libertad enorme a la hora no solo de guardar cualquier cosa dentro tu aplicación, sino de relacionar tablas, eliminar datos en cascada, hacer búsquedas y poblar nuestras TableViews en un santiamén. Como cosa de magia. Y además, sin escribir una sola línea de SQL, pese a que por debajo esté usando una SQL Lite. Para endulzarlo más, aprenderemos a hacerlo de tal forma que tratarás tu base de datos igual que como lo hacías hasta ahora con las clases y objetos de tu modelo: a través de métodos y propiedades.

Suena interesante, ¿no? Vamos a ello.

Conceptos básicos. Qué necesitas saber.

Qué son:

  • Las Entidades. Son las propias tablas de la base de datos. Para que nos hagamos una idea rápida, representan las clases del modelo de nuestra aplicación; es decir, las filas dentro de una tabla.
  • Los Atributos. Corresponden a las propiedades de cada objeto. En este punto lo dejaremos en que se parecen a las columnas en una tabla.
  • Las Relaciones. Representan las correspondencias entre las entidades. Esta es una de las principales ventajas que encuentro al usar Core Data. No necesitas simular una conexión entre objetos, ya que puedes definirla en el propio modelo de datos. ¿Que una tabla se compone de elementos que están en otra? No hay problema, tan solo define si son de uno a varios o de varios a varios, que Core Data hace el esto.

Con que tengas claros estos tres, podemos pasar a la arquitectura de Core Data.

En qué consisten los:

  • Managed Object Model (MOM). Es el modelo de la app. Aquí es donde se definen las entidades, atributos y relaciones mencionadas antes. Se define en un archivo de extensión .xcdatamodeld. Lo usarás para definir qué entidades necesitas, qué propiedades tienen y cómo se relacionan entre ellas.
  • Managed Object Context (MOC). Viene a ser un intermediario muy eficaz entre todo ese entramado de datos y nosotros. Carga en memoria los objetos que necesitamos, y efectivamente, nos permite interactuar con ellos (leerlos, guardarlos, eliminarlos, etc). Es nuestro chico de los recados. Debes crear una instancia de él en el código de manera temprana, al igual que lo hacías con tu modelo, porque nos hará falta hasta para ir al baño.
  • Persistent Store Coordinator (PSC). Se comunica con el MOC que acabamos de ver, y su labor consiste en hacer que los datos pasen en fila india, por decirlo de alguna manera. Gracias a él no tenemos que preocuparnos de no corromper los datos. Es la pieza clave que relaciona los datos cargados en memoria (MOC), el acceso a disco, y el modelo que hemos creado (MOM).
  • Persistent Object Store (POS). Él se encarga de negociar directamente con la base de datos, que en la gran mayoría de los casos (si no quieres hacer de tu vida un Infierno), será SQLite.
esquema gráfico de core data

©Apple. Esquema interno de Core Data

Y ahora vienen los sudores fríos… ¿Qué pasa si ya he creado mi proyecto pero no le he indicado que quiero usar el único, incomparable, grande y todopoderoso Core Data?

Nada. Es más, mejor incluso. Cuando quieras crear una aplicación con Core Data, lo primero de lo que tienes que asegurarte es de no seleccionar ‘Core Data’ dentro del asistente de creación de proyecto. Ahora veremos por qué.

Nuevo proyecto. Asegúrate de tener desmarcada la casilla 'Core Data'

Nuevo proyecto. Asegúrate de tener desmarcada la casilla ‘Core Data’

Si en este punto no has creado el proyecto, hazlo con la plantilla ‘Empty Application’.

Simplemente te faltará el archivo del diagrama del modelo, el MOM, ese con la extensión .xcdatamodeld. También te faltará la plantilla que por cierto nuestro amigo Xcode te crea por defecto en App Delegate, para inicializar Core Data.

¡¿Cómo?! ¡¿Dentro del AppDelegate?! Sí, en el didFinishLaunchingWithOptions concretamente. El que creó la plantilla debió de hacerla un viernes a las seis menos cuarto, y se quedó tan a gusto. Nosotros, que tenemos amor por el buen código, no queremos perpetrarlo desde la línea uno, así que nos creamos una clase aparte. Es recomendable llamar a esta clase (tu prefijo)CoreDataStack. Si te preguntas por qué, recuerda el Principio de Responsabilidad Única. En App Delegate solo deberían estar aquellos métodos relacionados con los eventos que nos manda el delegado de nuestra aplicación. La lógica de Core Data no tiene cabida en un lugar como este.

Puedes añadir un modelo de Core Data simplemente creándolo desde nuevo archivo.

Archivo -> Nuevo -> Archivo -> [dentro de Core Data] -> DataModel

No se requieren más pasos. Recuerda que lo hacemos con Objective-C. Si lo estás haciendo con Swift, tendrás que adaptar el código tú mismo.

Nota: Crea una carpeta llamada Model tanto dentro de la jerarquía de archivos como dentro de la organización de tu proyecto. Aunque si eres de los que nunca se hacen la cama, puedes omitir lo que acabas de leer.

En CoreDataStack.h deberías tener lo siguiente:

Si te fijas bien, son las propiedades que hemos visto anteriormente, así que de momento, todo controlado. Esos dos métodos sirven para guardar el estado del contexto y para recuperar el directorio de donde guardamos los datos. Por manejabilidad, nada más.

Ahora copia esto dentro del fichero de implementación (CoreDataStack.m).  Ya viene con algunos comentarios. Ten cuidado con el archivo de cabecera que importas y el nombre de la clase.

Ojo cuidado con el nombre que le pusiste al tu archivo .xcdatamodeld. Escribe en la constante #define del .m el nombre sin la extensión porque el CoreDataStack lo va a necesitar para un par de cosas. Yo llamé al archivo ‘Model’, así que no tengo que hacer cambios.

Manejo de los datos.

Como hemos visto, el Managed Object Context (MOC) maneja toda la información que viaja por la aplicación, pero no hemos mencionado nada sobre cómo la tratamos, cómo llamamos a esos ‘pedazos de datos’ de nuestro modelo, o dicho de otra forma, de qué objetos se compone el Contexto. Pues nada más y nada menos que de objetos de la clase NSManagedObject.

‘¡Pero cabrón rufián, no habías dicho nada de este!’  Eso es porque lo veremos un poco más adelante, cuando llegue el momento. Vete haciéndote la idea de que lo vamos a necesitar, pero de momento no te preocupes por él.

Ahora bien, basta de charla y vamos a lo que vamos: modelado de datos.

Si has llegado hasta aquí, aprovecha para hacer una visita al baño, lávate las manos y asegúrate de que lo has entendido todo, que vamos de seguido.

Lo primero de todo abrimos el archivo .xdatamodeld.

xcdatamodeld

Este es el archivo en el que vas a dibujar las tablas, tu modelo. No te preocupes por cómo vas a entenderte con ellas de momento.

Esa es la pinta que tendría que tener el modelo de tu aplicación en unos diez minutos.

¡Pues vamos a ello!

Primero de todo, si estás bien situado sobre el archivo (nombre del modelo).xcdatamodeld verás en la parte inferior del panel central aparece un botón para añadir una nueva entidad (‘New Entity‘). Vamos a crear la primera. La vamos a llamar ‘Character‘. Le puedes cambiar el nombre desde el inspector de la izquierda, tal y como lo harías con cualquier otro archivo o carpeta. Ahora rellenamos los datos como en la imagen, añadiendo cada uno con el botón de añadir de la sección ‘Attributes‘.

find_entity_name_cd

Asegúrate de escribir bien los nombres y los tipos, así que revisa los campos antes de continuar. Los tipos de dato son los que conoces, excepto el transformable, que veremos más adelante. Y por cierto, el tipo ‘Binary Data‘ lo usaremos para guardar datos como imágenes o sonido (no se te ocurra decir la palabra ‘blob’, tengamos la fiesta en paz). Una ventaja que tiene este tipo de atributo es que, al tratarse de archivos grandes generalmente, puedes decirle a Core Data que los almacene de manera externa y que maneje una referencia según el tamaño que tengan. Nunca tendrás que preocuparte de dónde están guardados ni de cómo, así que si necesitas marcar ‘Allows external storage’ en el inspector de atributos, hazlo sin miedo.

Si uno de tus personajes es Cthulhu, más vale que le pongas un Integer de 64 a la edad. Si no, con uno de 32 te vale.

Ya tienes tu primera tabla. ¿Fácil, no? ¡Y ni una línea de SQL! Puede sonarte a algo similar a cualquier DAO, pero, como verás más adelante, no nos vamos a quedar en esto. Core Data nos da mucho más. Paciencia, pequeño saltamontes.

Antes de seguir creando tablas, quiero que echemos un vistazo rápido al inspector de atributos. Lo encontrarás desplegando el panel derecho (Utilities Inspector). Selecciona la última ‘pestaña’ (por llamarlo de alguna forma), la que tiene el símbolo de Core Data.

attributes_inspector_character_cd

Vamos a seleccionar todos los valores como opcionales excepto el nombre, que queremos que sea obligatorio. Pero ¿qué son los campos optional, index y transient?

  1. Index: Convierte este campo en un índice para las búsquedas.
  2. Transient: Simplemente indica a la base de datos que este valor estará en memoria pero que será completamente volátil, que no lo queremos guardar. De esta forma lo podremos usar en tiempo de ejecución e ignorarlo al guardar. Digamos que este ‘está de paso’. No le daremos uso en este tutorial, y tampoco se usa demasiado, así que no te preocupes por él.
  3. Optional: Como su nombre indica, este valor es opcional. Dejar desmarcada esta casilla nos obligaría a tener siempre un valor no nulo en ella. Es útil para evitarnos despistes en ciertos campos importantes. Solo dejaremos como obligatorio el del nombre.

Sin salir del inspector, cambia de atributo e investiga qué opciones tienes a tu disposición según el tipo de dato de cada campo/atributo. Algunos te dejarán asignar valores por defecto (perfecto para que nunca estén vacíos) y además asignar un valor máximo y mínimo, como en el caso de los números.

Dicho esto, estás capacitado para cumplimentar otras dos tablas por tu cuenta. Tan solo ten cuidado en asignar qué tipos a qué campos al terminar, porque el asistente gráfico de CoreData es algo puñetero y en ocasiones reordena los campos sin que te des cuenta. No es un consejo baladí, puede salvarte de unos cuantos dolores de cabeza, así que acostúmbrate a revisar los campos siempre. Los tipos que desarrollaron este sistema comparten vestuario con los que decidieron hacer la plantilla de CoreData en AppDelegate.

Aquí tienes la imágenes. Es totalmente trivial.

new_entity_race_cd new_entity_scenario_cd

Ya tenemos nuestras tres tablas. No estaría mal verlas de forma gráfica, porque así no es que tenga mucha pinta de base de datos. Vamos a cambiar esto.

Vista Relaciones

Con el botón de la parte inferior derecha puedes alternar entre los dos estilos de presentación. El que usábamos hasta ahora era mejor para cumplimentar las tablas, mientras que este es bastante mejor para contemplar la estructura completa y sus relaciones.

¿Cómo que qué relaciones? ¡Qué despiste! ¡Ahora mismo las creamos!

Relaciones entre tablas

Asegúrate de haber entendido todo el proceso hasta este punto, que vamos a crear las relaciones entre las tablas.

Lo primero de todo, es importante saber de antemano qué campos vamos a relacionar con qué campos antes de empezar. Core Data se encargará de todo lo demás, pero convendría tenerlo muy claro porque hacer cambios puede llegar a ser engorroso conforme vamos ampliando las tablas y las relaciones… y peligroso.

No te preocupes, en este tutorial haremos una implementación sencilla, como en la imagen de arriba:

¿Cómo conseguimos esto?

Volvamos a la vista detalle de las tablas, con la que hemos comenzado, y vamos a empezar a relacionar las tablas.

Character

Character

Scenario

Nos colocamos en la sección ‘Relationships’ ( que viene a ser como el Badoo de las BBDD relacionales en CoreData), y seleccionamos ‘Character‘. Aquí, tal y como hacíamos más arriba, creamos un campo nuevo. Lo vamos a llamar ‘homeLand‘, que vendrá a representar el lugar de nacimiento de un personaje. No queremos que sea una simple cadena de texto, así que le asignamos un campo de tipo ‘Scenario‘ en Destination. Deja la tercera columna vacía.

Cuando hayamos terminado con ‘Character’, seleccionamos ‘Scenario’. Has adivinado bien, a esta entidad le decimos que tiene una relación con ‘Character’. Creamos una nueva relación dentro de ‘Relationships’ y la llamamos ‘inhabitant’, puesto que, desde la perspectiva del escenario, el personaje es un habitante más, y en esta ocasión seleccionamos ‘Character’ en Destination. Y ahora sí, desplegamos los valores de la tercera columna y elegimos la única opción que nos da en Inverse:  ‘homeLand’. Ahora ya tenemos una relación simple entre Personaje y Escenario.

No, espera, falta algo…

 

Definición de las relaciones entre tablas

Si ya has trabajado anteriormente con bases de datos ya sabrás que hay que definir exactamente qué tipo de relación numérica existe entre ellas. Si nunca has tocado una línea de SQL o simplemente no lo recuerdas, ponte el gorro de pensar y lee atentamente, que nos tenemos que poner serios un momento. Te explico.

Estos son los tipos de relaciones entre tablas:

  • Uno a varios: Un campo de cierta entidad puede estar relacionada con varios valores de la otra; sin embargo, la segunda entidad solo puede estar relacionada con un campo de la primera. Por ejemplo, si tenemos una tabla de Clientes y otra de Pedidos, podríamos determinar que un Cliente puede hacer varios pedidos, pero un pedido solo puede estar relacionado con un solo cliente.
  • Varios a varios: Un campo de cierta entidad puede estar relacionado con varios valores de otra, y viceversa. Por ejemplo, un alumno puede asistir a varias clases, y al mismo tiempo una clase puede tener varios alumnos en lista.
  • Uno a uno: Un campo de cierta entidad solo puede estar inequívocamente relacionado con un campo de la otra entidad. Por ejemplo, un país puede tener un presidente, pero una persona solo puede ser presidenta de un país.

Asegúrate de haber entendido esto, porque vamos a ponernos manos a la obra.

Seleccionamos una de la relaciones dentro de ‘Relationships’. En este caso, vamos a empezar con la de nuestro querido ‘Character‘, y la que hemos llamado ‘homeLand‘. Abrimos el panel lateral derecho, y en mismo inspector de Core Data nos detenemos en la propiedad llamada ‘Type‘. Por defecto nos ha asignado un ‘To One‘. Esto es correcto, puesto que un personaje solo debería tener un lugar de nacimiento. Ahora bien, cualquier Scenario podría hospedar varios personajes, ¿verdad?

Nos movemos a ‘Scenario‘ de nuevo y seleccionamos la relación inversa, la de ‘inhabitant‘. Comprueba que esta también tiene asignado un solo campo de la entidad ‘Character’; sin embargo, acabamos de decir que un escenario puede ser el lugar de nacimiento de varios personajes, así que esto no está correcto. Desplegamos el selector y definimos la propiedad ‘To Many‘.

Ahora sí, ya tenemos una relación que define que un personaje puede estar relacionado con un lugar, y un lugar con varios personajes. Esto es, efectivamente, una relación ‘uno a varios‘. Se la denomina técnicamente y por abreviar una relación 1:N.

Imagen tipo de propiedades de una relación en Scenarios

Imagen tipo de propiedades de una relación en Scenarios

Antes de abandonar esta sección, vamos a detenernos a mirar una última vez al resto de propiedades:

  1. La primera sección sirve para modificar el nombre de la relación .
  2. La segunda determina nombre del campo opuesto en la entidad destino. Esto sería similar a establecer una FOREIGN_KEY. También podemos determinar qué tipo de relación de dependencia existe entre estos campos en la propiedad ‘Delete Rule’. Aquí tenemos cuatro opciones: No action, Nullify, Cascade y Deny. Normalmente nos interesará la segunda (Nullify) para que el campo opuesto quede asignado a nil si borramos el de esta tabla. El de ‘Cascade’ lo que hace es llevarse consigo todos los campos relacionados en caso de eliminación. Si, por ejemplo, eliminamos un cliente, que todos sus pedidos relacionados se borren también de la base de datos.
  3. La tercera establece como hemos visto los tipos de relación entre campos de distintas entidades/tablas.

Ahora que ya conocemos lo básico para crear relaciones y tenemos nuestras tablas creadas, vamos a terminar de relacionarlas como Jobs manda.

En este punto ya estás capacitado para hacerlo por tu cuenta, así que aquí van los detalles de las relaciones. Tómalo como ejercicio personal.

  • Un personaje puede ser líder de una raza, y una raza solo puede tener un líder.
  • Una raza puede tener un líder, pero un líder solo puede serlo de una sola raza.
  • Una raza puede tener asignado a varios territorios, y un territorio puede contener varias razas.
  • Un escenario puede tener varios personajes, pero un personaje solo puede pertenecer a un territorio.
  • Un escenario puede contener varias razas, pero una raza puede estar en varios territorios.
Character

Character

Race

Race

Scenario

Scenario

Fíjate en que he actualizado los nombres de las relaciones para que sean semánticas. Si son ‘a varios’, las escribimos en plural, si es única, en singular. Cuando nos peleemos con el código será de gran utilidad.

Eso es todo amigos

Aquí finaliza la primera parte de este pequeño tutorial para aprender Core Data. Ya conoces los componentes estructurales del Framework, qué base de datos utilizamos, de qué se componen las tablas, cómo se tratan, cómo se crean, qué son las relaciones, y qué son las propiedades de cada uno de los anteriores.

En el próximo artículo veremos cómo guardar datos y aprenderemos a recuperarlos y cargarlos en pantalla. Hasta entonces, repasa lo visto y si quieres, crea tu proyecto propio y desarrolla tu modelo como hemos visto aquí.

¡Nos vemos en el siguiente!

Escrito por Miguel Hernández Jaso

Autor del blog. Desarrollador especializado en iOS.

4 respuestas a “Semillas de Cacao: Core Data – Introducción”

  1. Muy buen post. Gracias por compartir el conocimiento. Una pregunta, es mejor utilizar Core Data directamente o un framework que nos facilite utilizarlo?

  2. Muchas gracias por realizar esta guía. Aún no la he acabado de leer pero me está sirviendo mucho para comprender Core Data y ampliar mis conocimientos sobre esto. Mi intención es meterlo dentro del temario del ciclo formativo del que imparto clases.

    Gracias.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Mi Gobierno me obliga a decirle que utilizo 'cookies' en mi página. Si continúa navegando, quiere decir que está conforme con ello.