Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Core Data
Code

Core Data desde cero: migraciones

by
Difficulty:IntermediateLength:LongLanguages:
This post is part of a series called Core Data from Scratch.
Core Data from Scratch: More NSFetchedResultsController
Core Data from Scratch: Subclassing NSManagedObject

Spanish (Español) translation by Elías Nicolás (you can also view the original English article)

En los artículos anteriores de esta serie, hemos encontrado un problema molesto que debemos abordar. Cada vez que modificamos el modelo de datos de una aplicación Core Data, el almacenamiento persistente se vuelve incompatible con el modelo de datos. El resultado es un bloqueo al iniciarse, lo que hace que la aplicación sea inutilizable, un problema grave si esto le sucede a una aplicación en la App Store.

Nuestra aplicación se bloquea porque invocamos abort en el método persistentStoreCoordinator si no se logra agregar el almacén persistente al coordinador de tienda persistente. Para que quede claro, la función abort hace que la aplicación se cierre de inmediato.

Sin embargo, no es necesario finalizar nuestra aplicación, y mucho menos bloquearla. Si Core Data nos dice que el modelo de datos y el almacenamiento persistente son incompatibles, nos corresponde a nosotros resolverlo.

En este artículo, analizaremos dos opciones para recuperarse de tal situación, migrar el almacén persistente y crear un nuevo almacén persistente que sea compatible con el modelo de datos modificado.

1. el problema

Permítanme primero aclarar el problema que estamos tratando de resolver. Descargue el proyecto de muestra que creamos en el artículo anterior y ejecútelo en el simulador de iOS. La aplicación debería funcionar y funcionar bien.

Abra Done.xcdatamodeld y agregue un atributo updatedAt de tipo Date a la entidad TSPItem. Ejecute la aplicación una vez más y observe cómo la aplicación se bloquea tan pronto como se inicia. Afortunadamente, Core Data nos da una pista de lo que salió mal. Echa un vistazo a la salida en la consola de Xcode.

En la última línea, Core Data nos dice que el modelo de datos que se utilizó para abrir el almacén persistente es incompatible con el modelo de datos que utilizó para crear el almacén persistente. Espere. ¿Qué?

Cuando lanzamos la aplicación por primera vez, Core Data creó una base de datos SQLite basada en el modelo de datos. Sin embargo, debido a que cambiamos el modelo de datos agregando un atributo a la entidad TSPItem, updatedAt, Core Data ya no entiende cómo debe almacenar los registros TSPItem en la base de datos SQLite. En otras palabras, el modelo de datos modificado ya no es compatible con el almacén persistente que creó anteriormente.

2. La solución

Afortunadamente para nosotros, algunos ingenieros inteligentes de Apple han creado una solución para modificar de forma segura un modelo de datos sin tener problemas de incompatibilidad. Para resolver el problema al que nos enfrentamos, debemos encontrar una manera de decirle a Core Data cómo una versión del modelo de datos se relaciona con otra. Eso es correcto, la versión del modelo de datos es parte de la solución.

Con esa información, Core Data puede comprender cómo se debe actualizar el almacén persistente para que sea compatible con el modelo de datos modificado, es decir, la nueva versión del modelo de datos. En otras palabras, debemos entregar a Core Data la información necesaria para migrar el almacén persistente de una versión del modelo de datos a otra.

3. Migraciones

Hay dos tipos de migraciones, ligeras y pesadas. Las palabras lightweight y heavy son bastante descriptivas, pero es importante que entienda cómo Core Data maneja cada tipo de migración.

Migraciones ligeras

Las migraciones ligeras requieren muy poco trabajo de su parte, el desarrollador. Recomiendo encarecidamente que elija una migración ligera en lugar de una gran migración siempre que pueda. El costo de una migración ligera es sustancialmente más bajo que el de una migración pesada.

Por supuesto, la otra cara de las migraciones ligeras es que son menos poderosas que las migraciones pesadas. Los cambios que puede realizar en un modelo de datos con migraciones ligeras son limitados. Por ejemplo, una migración ligera le permite agregar o renombrar atributos y entidades, pero no puede modificar el tipo de atributo o las relaciones entre las entidades existentes.

Las migraciones ligeras son ideales para expandir el modelo de datos, agregar atributos y entidades. Si planea modificar las relaciones o cambiar los tipos de atributos, entonces se encontrará con un viaje salvaje con grandes migraciones.

Migraciones pesadas

Las migraciones pesadas son un poco más complicadas. Déjame reformular eso. Las migraciones intensas son un dolor en el cuello y debes tratar de evitarlas si es posible. Las migraciones pesadas son poderosas, pero ese poder tiene un costo. Las migraciones pesadas requieren mucho trabajo y pruebas para asegurarse de que la migración se complete con éxito y, lo que es más importante, sin pérdida de datos.

Entramos en el mundo de las migraciones pesadas si realizamos cambios que los Datos básicos no pueden inferir automáticamente comparando las versiones del modelo de datos. Los datos básicos necesitarán un modelo de mapeo para comprender cómo las versiones del modelo de datos se relacionan entre sí. Debido a que las migraciones pesadas son un tema complejo, no lo cubriremos en esta serie.

4. Versiones

Si has trabajado con Ruby on Rails, entonces las migraciones tendrán mucho sentido para ti. La idea es simple pero poderosa. Core Data nos permite la versión del modelo de datos y esto nos permite modificar de forma segura el modelo de datos. Core Data inspecciona el modelo de datos versionado para comprender cómo el almacenamiento persistente se relaciona con el modelo de datos. Al observar el modelo de datos versionado, también sabe si es necesario migrar el almacén persistente antes de poder utilizarlo con la versión actual del modelo de datos.

Versiones y migraciones van de la mano. Si desea comprender cómo funcionan las migraciones, primero tendrá que entender cómo versionar el modelo de datos Core Data. Revisemos la aplicación de tareas que creamos en el artículo anterior. Como vimos anteriormente, agregar un atributo, updatedAt, a la entidad TSPItem hace que el almacén persistente sea incompatible con el modelo de datos modificado. Ahora entendemos la causa de esto.

Comencemos con una pizarra limpia abriendo Done.xcdatamodeld y eliminando el atributo updatedAt de la entidad TSPItem. Es hora de crear una nueva versión del modelo de datos.

Con el modelo de datos seleccionado, elija Add Model Version...en el menú Editor. Xcode le pedirá que nombre la nueva versión del modelo de datos y, lo que es más importante, en qué versión debe basarse. Para garantizar que Core Data pueda migrar el almacén persistente para nosotros, es importante que elija la versión anterior del modelo de datos. En este ejemplo, solo tenemos una opción.

El resultado de esta acción es que ahora podemos ver tres archivos de modelos de datos en el Project Navigator. Hay un modelo de datos de nivel superior con una extensión .xcdatamodeld y dos hijos con una extensión .xcdatamodel.

Puede ver el archivo .xcdatamodeld como un paquete para las versiones del modelo de datos, con cada versión representada por un archivo .xcdatamodel. Puede verificar esto haciendo clic derecho en el archivo .xcdatamodeld y seleccionando Show in Finder. Esto te llevará al modelo de datos en el proyecto Xcode. Si hace clic con el botón derecho en ese archivo y selecciona Show Package Contents, debería ver las dos versiones del modelo de datos, Done.xcdatamodel y Done 2.xcdatamodel

¿Ha notado en el Project Navigator que una de las versiones tiene una marca de verificación verde? Esta marca de verificación indica cuál es la versión del modelo actual, Done.xcdatamodel en este ejemplo. En otras palabras, aunque hemos creado una nueva versión del modelo de datos, nuestra aplicación aún no la ha utilizado. Sin embargo, antes de cambiar esto, debemos decirle a Core Data qué debe hacer con el modelo de datos versionado.

Necesitamos decirle a Core Data cómo migrar el almacén persistente para el modelo de datos. Hacemos esto en el método persistentStoreCoordinator en TSPAppDelegate.m. En el método persistentStoreCoordinator, creamos el coordinador de tienda persistente y le agregamos un almacén persistente invocando addPersistentStoreWithType:configuration:URL:optionsaddPersistentStoreWithType:. Esto no es nada nuevo.

El cuarto parámetro de este método, un diccionario de opciones, es actualmente nil. Este diccionario de opciones incluye instrucciones para Core Data. Nos da la oportunidad de decirle al coordinador de la tienda persistente cómo debe migrar la tienda persistente que le agregamos.

Eche un vistazo a la implementación actualizada de persistentStoreCoordinator en la que pasamos un diccionario de opciones con dos pares clave-valor.

La primera clave, NSMigratePersistentStoresAutomaticallyOption, le dice a Core Data que nos gustaría que intentemos migrar el almacén persistente para nosotros. La segunda clave, NSInferMappingModelAutomaticallyOption, instruye a Core Data a inferir el modelo de mapeo para la migración. Esto es exactamente lo que queremos. Debería funcionar sin problemas, siempre y cuando se trate de una migración ligera.

Con este cambio, estamos listos para migrar el modelo de datos a la nueva versión que creamos hace unos momentos. Comience seleccionando la nueva versión, Done 2.xcdatamodel, y agregue un nuevo atributo updatedAt de tipo Date a la entidad TSPItem.

También debemos marcar la nueva versión del modelo de datos como la versión que utilizará Core Data. Seleccione Done.xcdatamodeld en el Project Navigator y abra el File Inspector a la derecha. En la sección Model Version, establezca Current en Done 2.

En el Project Navigator, Done 2.xcdatamodel ahora debería tener una marca de verificación verde en lugar de Done.xcdatamodel.

Con este cambio, puede construir y ejecutar la aplicación de forma segura. Si ha seguido los pasos anteriores, Core Data debería migrar automáticamente el almacén persistente para usted inferiendo el modelo de mapeo basado en el modelo de datos versionado.

Tenga en cuenta que hay algunas advertencias que debe tener en cuenta. Si te encuentras con un accidente, entonces has hecho algo mal. Por ejemplo, si configuró la versión del modelo de datos en Done 2.xcdatamodel, ejecutó la aplicación y luego realizó cambios en Done 2.xcdatamodel, entonces inevitablemente se encontrará con un bloqueo debido a que la tienda persistente es incompatible con el modelo de datos. Las migraciones ligeras son relativamente poderosas y fáciles de implementar, pero eso no significa que pueda modificar el modelo de datos en cualquier momento.

La capa de datos de un proyecto de software requiere cuidado, atención y preparación. Las migraciones son grandes, pero deben usarse con moderación. Las caídas no son un problema durante el desarrollo, pero son catastróficas en la producción. En la siguiente sección, analizaremos más de cerca lo que esto significa y cómo evitar bloqueos debido a una migración problemática.

5. Evitando los crashes.

Nunca me he topado con una situación que justifique la llamada abort en producción y me duele cuando navego en un proyecto en el que se usa la implementación predeterminada de Apple para configurar la pila de datos principales, en la que se cancela abort cuando se agrega un almacén persistente.

Evitar abort no es tan difícil, pero requiere algunas líneas de código e informar al usuario sobre lo que salió mal en caso de que algo salga mal. Los desarrolladores son humanos y todos cometemos errores.

Paso 1: Deshacerse de abort

Comience abriendo TSPAppDelegate.m y elimine la línea en la que llamamos abort. Ese es el primer paso para un usuario feliz.

Paso 2: Mover la tienda incompatible

Si Core Data detecta que el almacén persistente es incompatible con el modelo de datos, primero movemos el almacén incompatible a una ubicación segura. Hacemos esto para asegurarnos de que los datos del usuario no se pierdan. Incluso si el modelo de datos es incompatible con el almacén persistente, es posible que pueda recuperar los datos del mismo. Eche un vistazo a la implementación actualizada del método persistentStoreCoordinator en TSPAppDelegate.m.

Tenga en cuenta que he cambiado el valor de storeURL, la ubicación del almacén persistente. Apunta a un directorio en el directorio documents en la sandbox de la aplicación. La implementación de applicationStoresDirectory, un método auxiliar, es sencilla, como puede ver a continuación.

Si el coordinador de la tienda persistente no puede agregar la tienda persistente existente en storeURL, moveremos la tienda persistente a un directorio separado. Tenga en cuenta que utilizamos otros dos métodos de ayuda, applicationIncompatibleStoresDirectory y nameForIncompatibleStore. La implementación de applicationIncompatibleStoresDirectory es bastante simple, como puede ver a continuación.

En nameForIncompatibleStore, generamos un nombre para el almacén incompatible en función de la fecha y hora actuales para evitar nombrar colisiones.

Paso 3: Creando una nueva tienda persistente

Es hora de crear un nuevo almacén persistente para finalizar la configuración de la pila de datos básicos. Las siguientes líneas deben parecer muy familiares a estas alturas.

Si Core Data no puede crear un nuevo almacén persistente, entonces hay problemas más serios que no están relacionados con que el modelo de datos sea incompatible con el almacén persistente. Si se encuentra con este problema, entonces vuelva a verificar el valor de storeURL.

Paso 4: Notificar al usuario

Este paso es probablemente el más importante en términos de crear una aplicación fácil de usar. Perder los datos del usuario es una cosa, pero fingir que no ha pasado nada no es agradable. ¿Cómo te sentirías si una aerolínea perdiera tu equipaje, simulando que no pasó nada?

Mostramos una vista de alerta al usuario, pero es una buena idea dar un paso más. Por ejemplo, puede recomendarles que se pongan en contacto con el servicio de asistencia técnica e incluso pueden implementar una función que les permita enviarle el almacén corrupto. Este último es muy útil para depurar el problema.

Paso 5: Pruebas

La persistencia de datos es un aspecto importante de la mayoría de las aplicaciones. Por lo tanto, es importante probar adecuadamente lo que hemos implementado en este artículo. Para probar nuestra estrategia de recuperación, ejecute la aplicación en el Simulador de iOS y compruebe que el almacén persistente se haya creado correctamente en el directorio Application Support, en el subdirectorio Stores.

Agregue un nuevo atributo a la entidad TSPItem en Done 2.xcdatamodel y ejecute la aplicación una vez más. Debido a que el almacén persistente existente ahora es incompatible con el modelo de datos, el almacén persistente incompatible se mueve al subdirectorio Incompatible y se crea un nuevo almacén persistente. También debería ver una vista de alerta, informando al usuario sobre el problema.

Conclusión

Las migraciones son un tema importante si planea hacer un uso extensivo de los Datos Core. Las migraciones le permiten modificar de forma segura el modelo de datos de su aplicación y, en el caso de migraciones ligeras, sin grandes esfuerzos.

En el siguiente artículo, nos centramos en la subclasificación de NSManagedObject. Si un proyecto de Core Data tiene algún tipo de complejidad, la subclase de NSManagedObject es el camino a seguir.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.