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

Datos básicos desde cero: objetos gestionados y solicitudes de recuperación

by
Difficulty:IntermediateLength:LongLanguages:
This post is part of a series called Core Data from Scratch.
Core Data from Scratch: Data Model
Core Data from Scratch: Relationships and More Fetching

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

Con todo acerca de los modelos de datos de Cora Data aún frescos en su mente, es hora de comenzar a trabajar con Core Data. En este artículo, conocemos NSManagedObject, la clase con la que más interactuarás cuando trabajes con Core Data. Aprenderá a crear, leer, actualizar y eliminar registros.

También conocerá algunas otras clases de Core Data, como NSFetchRequest y NSEntityDescription. Permítame comenzar presentándole a NSManagedObject, su nuevo mejor amigo.

1. Objetos gestionados

Las instancias de NSManagedObject representan un registro en el almacén de respaldo de Core Data. Recuerda, no importa cómo se vea esa tienda de respaldo. Sin embargo, para revisar la analogía de la base de datos, una instancia de NSManagedObject contiene la información de una fila en una tabla de base de datos.

La razón por la que Core Data utiliza NSManagedObject en lugar de NSObject como su clase base para modelar registros tendrá más sentido un poco más adelante. Antes de comenzar a trabajar con NSManagedObject, necesitamos saber algunas cosas sobre esta clase.

NSEntityDescription

Cada instancia de NSManagedObject está asociada con una instancia de NSEntityDescription. La descripción de la entidad incluye información sobre el objeto gestionado, como entity del objeto gestionado y sus attributes y relationships.

NSManagedObjectContext

Un objeto gestionado también está vinculado a una instancia de NSManagedObjectContext. El contexto del objeto gestionado al que pertenece un objeto gestionado, supervisa los cambios en el objeto gestionado.

2. Creando un Registro

Con lo anterior en mente, crear un objeto gestionado es bastante sencillo. Para asegurarse de que un objeto administrado esté configurado correctamente, se recomienda usar el inicializador designado para crear nuevas instancias de NSManagedObject. Veamos cómo funciona esto creando un nuevo objeto person.

Abra el proyecto del artículo anterior o clónelo desde GitHub. Debido a que no construiremos una aplicación funcional en este artículo, haremos la mayor parte de nuestro trabajo en la clase de delegado de aplicación, TSPAppDelegate. Abra TSPAppDelegate.m y actualice la implementación de la application:didFinishLaunchingWithOptions: como se muestra a continuación.

Lo primero que hacemos es crear una instancia de la clase NSEntityDescription invocando entityForName:inManagedObjectContext:. Pasamos el nombre de la entidad para la que queremos crear un objeto administrado, @"Person", y una instancia de NSManagedObjectContext.

¿Por qué necesitamos pasar un objeto NSManagedObjectContext? Especificamos el nombre para el que queremos crear un objeto administrado, pero también necesitamos decirle a Core Data dónde puede encontrar el modelo de datos para esa entidad. Recuerde que un contexto de objeto gestionado está vinculado a un coordinador de tienda persistente y un coordinador de tienda persistente mantiene una referencia a un modelo de datos. Cuando pasamos en un contexto de objeto gestionado, Core Data solicita a su coordinador de tienda persistente su modelo de datos para encontrar la entidad que estamos buscando.

En el segundo paso, invocamos el inicializador designado de la clase NSManagedObject, initWithEntity:insertIntoManagedObjectContext:. Pasamos en la descripción de la entidad y una instancia de NSManagedObjectContext. ¿Espera? ¿Por qué necesitamos pasar en otra instancia de NSManagedObjectContext? Recuerda lo que escribí antes. Un objeto gestionado está asociado con una descripción de entidad y vive en un contexto de objeto gestionado, por lo que le informamos a Core Data a qué contexto de objeto gestionado se debe vincular el nuevo objeto gestionado.

Esto no es demasiado complejo, ¿verdad? Ahora hemos creado un nuevo objeto de persona. ¿Cómo cambiamos sus atributos o definimos una relación? Esto se hace aprovechando la codificación clave-valor. Para cambiar el primer nombre del nuevo objeto de persona que acabamos de crear, hacemos lo siguiente.

Si está familiarizado con la codificación de clave-valor, esto debería parecer muy familiar. Debido a que la clase NSManagedObject admite la codificación de clave-valor, cambiamos un atributo invocando setValue:forKey:. Es así de simple.

Una desventaja de este enfoque es la facilidad con la que puede introducir errores al escribir incorrectamente un atributo o nombre de relación. Además, Xcode no autocompleta automáticamente los nombres de los atributos, como, por ejemplo, los nombres de propiedades. Podemos solucionar este problema, pero eso es algo que veremos más adelante en esta serie.

Antes de continuar nuestra exploración de NSManagedObject, establezcamos age de newPerson en 44.

Si no está familiarizado con la codificación de clave-valor, es posible que se sorprenda de que hayamos pasado un literal de NSNumber en lugar de un entero, como definimos en nuestro modelo de datos. El método setValue:forKey: solo acepta objetos, no primitivos. Mantén esto en mente.

3. Guardando un registro

A pesar de que ahora tenemos una nueva instancia de persona, Core Data aún no ha guardado a la persona en su tienda de respaldo. El objeto administrado que creamos actualmente vive en el contexto del objeto administrado en el que se insertó. Para guardar el objeto de persona en el almacén de respaldo, debemos guardar los cambios del contexto del objeto gestionado llamando a save: en él.

El método save: devuelve un valor booleano para indicar el resultado de la operación de guardar y acepta un puntero a un objeto NSerror, que nos dice qué fue lo que falló si la operación de guardar no tiene éxito. Eche un vistazo al siguiente bloque de código para aclararlo.

Genere y ejecute la aplicación para ver si todo funciona como se espera. ¿También te encontraste con un accidente? ¿Qué te dijo la salida de la consola? ¿Se veía similar a la salida de abajo?

Xcode nos dice que esperaba una instancia de NSDate para el atributo first, pero pasamos en una NSString. Si abre el modelo de datos básicos que creamos en el artículo anterior, verá que el tipo del atributo first es, de hecho, Date. Cámbiala a String y ejecuta la aplicación una vez más.

¿Otro fallo? A pesar de que este es un tema más avanzado, es importante entender qué está pasando.

Compatibilidad del modelo de datos

La salida en la consola de Xcode debe ser similar a la salida que se muestra a continuación. Tenga en cuenta que el error es diferente del anterior. Xcode nos dice que el modelo para abrir la tienda es incompatible con el que se usó para crear la tienda. ¿Cómo pasó esto?

Cuando lanzamos la aplicación por primera vez hace unos momentos, Core Data inspeccionó el modelo de datos y, en base a ese modelo, creó una tienda para nosotros, una base de datos SQLite en este caso. Sin embargo, los datos básicos son inteligentes. Se asegura de que la estructura del almacén de respaldo y la del modelo de datos sean compatibles. Esto es vital para asegurarnos de que volvamos de la tienda de respaldo lo que esperamos y lo que ponemos allí en primer lugar.

Durante la primera caída, notamos que nuestro modelo de datos contenía un error y cambiamos el tipo del atributo first Date a String. En otras palabras, cambiamos el modelo de datos a pesar de que Core Data ya había creado el almacén de respaldo para nosotros basado en el modelo de datos incorrecto.

Después de actualizar el modelo de datos, iniciamos nuevamente la aplicación y encontramos el segundo bloqueo. Una de las cosas que Core Data hace cuando crea la pila de Core Data es asegurarse de que el modelo de datos y el almacén de respaldo (si existe) sean compatibles. Ese no fue el caso en nuestro ejemplo, por lo tanto, el accidente.

¿Cómo resolvemos esto? La solución fácil es eliminar la aplicación del dispositivo o del simulador de iOS y volver a iniciar la aplicación. Sin embargo, esto es algo que no puede hacer si ya tiene una aplicación en la App Store que la gente está usando. En ese caso, usted hace uso de las migraciones, que es algo que discutiremos en un artículo futuro.

Debido a que no tenemos millones de usuarios que utilizan nuestra aplicación, podemos eliminarla de forma segura de nuestro dispositivo de prueba y ejecutarla una vez más. Si todo salió bien, la nueva persona ahora está almacenada de forma segura en la tienda, la base de datos SQLite Core Data creada para nosotros.

Inspeccionando la tienda de respaldo

Puede verificar que la operación de guardar funcionó echando un vistazo dentro de la base de datos SQLite. Si ejecutó la aplicación en el Simulador de iOS, navegue hasta ~/<USER>/Library/Application Support/iPhone Simulator/<VERSION>/<OS>/Applications/<ID>/Documents/Core_Data.sqlite. Para hacer su vida más fácil, le recomiendo que instale SimPholders, una herramienta que hace que navegar por la ruta anterior sea mucho más fácil. Abra la base de datos SQLite e inspeccione la tabla llamada ZPERSON. La tabla debe tener una entrada, la que insertamos hace un minuto.

Debes tener en cuenta dos cosas. Primero, no hay necesidad de entender la estructura de la base de datos. Core Data administra la tienda de respaldo por nosotros y no necesitamos entender su estructura para trabajar con Core Data. En segundo lugar, nunca acceder a la tienda directamente. Core Data está a cargo de la tienda de respaldo y debemos respetarlo si queremos que Core Data haga su trabajo correctamente. Si comenzamos a interactuar con la base de datos SQLite, o con cualquier otra tienda, no hay garantía de que Core Data continúe funcionando correctamente. En resumen, Core Data está a cargo de la tienda, así que déjelo en paz.

4. Obteniendo Registros

Aunque veremos de cerca NSFetchRequest en el siguiente artículo, necesitamos que la clase NSFetchRequest solicite a Core Data información del gráfico de objetos que administra. Veamos cómo podemos recuperar el registro que insertamos anteriormente utilizando NSFetchRequest.

Después de inicializar la solicitud de recuperación, creamos un objeto NSEntityDescription y lo asignamos a la propiedad entity de la solicitud de obtención. Como puede ver, usamos la clase NSEntityDescription para indicar a Core Data en qué entidad estamos interesados.

La clase NSManagedObjectContext maneja la obtención de datos, invocamos executeFetchRequest:error:, pasando la solicitud de captura y un puntero a un objeto NSError. El método devuelve una matriz de resultados si la solicitud de recuperación es exitosa y nil si se encuentra un problema. Tenga en cuenta que Core Data siempre devuelve un objeto NSArray si la solicitud de recuperación es exitosa, incluso si esperamos un resultado o si Core Data no encontró ningún registro coincidente.

Ejecute la aplicación e inspeccione la salida en la consola de Xcode. A continuación puede ver lo que se devolvió, una matriz con un objeto de tipo NSManagedObject. La entidad del objeto es Person.

Para acceder a los atributos del registro, utilizamos la codificación de clave-valor como hicimos anteriormente. Es importante familiarizarse con la codificación de clave-valor si planea trabajar con Core Data.

Quizás se esté preguntando por qué registro el objeto person antes y después de registrar el nombre de person. Esta es en realidad una de las lecciones más importantes de este artículo. Echa un vistazo a la salida de abajo.

La primera vez que registramos el objeto person en la consola, vemos data: <fault>. Sin embargo, la segunda vez, data contienen el contenido de los atributos y relaciones del objeto. ¿Porqué es eso? Esto tiene todo que ver con las fallas, un concepto clave de Core Data.

5. Fallos

El concepto que subyace a la falla no es exclusivo de Core Data. Si alguna vez has trabajado con Active Record en Ruby on Rails, lo siguiente seguramente sonará. El concepto no es idéntico, pero es similar desde la perspectiva de un desarrollador.

Core Data intenta mantener su huella de memoria lo más baja posible y una de las estrategias que utiliza para lograrlo es la falla. Cuando recuperamos los registros de la entidad Person hace un momento, Core Data ejecutó la solicitud de recuperación, pero no inicializó completamente los objetos gestionados que representan los registros recuperados.

Lo que recibimos es un fallo, un objeto de marcador de posición que representa el registro. El objeto es de tipo NSManagedObject y podemos tratarlo como tal. Al no inicializar completamente el registro, Core Data mantiene baja su huella de memoria. No es un ahorro de memoria significativo en nuestro ejemplo, pero imagina lo que sucedería si obtuviéramos docenas, cientos o incluso miles de registros.

Las fallas generalmente no son nada de lo que deba preocuparse. En el momento en que accede a un atributo o relación de un objeto gestionado, se desencadena la falla, lo que significa que Core Data convierte la falla en un objeto administrado realizado. Puede ver esto en nuestro ejemplo y esa es también la razón por la que la segunda declaración de registro del objeto person no imprime un error en la consola.

Fallar es algo que hace tropezar a muchos recién llegados y, por lo tanto, quiero asegurarme de que comprende los conceptos básicos de este concepto. Aprenderemos más sobre fallar más adelante en esta serie.

6. Actualización de registros

Actualizar registros es tan simple como crear un nuevo registro. Obtiene el registro, cambia un atributo o relación y guarda el contexto del objeto administrado. La idea es la misma que cuando creas un registro. Debido a que el objeto administrado, el registro, está vinculado a un contexto de objeto administrado, este último es consciente de cualquier cambio, inserción y actualización. Cuando se guarda el contexto del objeto gestionado, Core Data propaga todo al almacén de respaldo.

Eche un vistazo al siguiente bloque de código en el que actualizamos el registro que obtuvimos cambiando la edad de la persona y guardando los cambios.

Puede verificar que la actualización fue exitosa echando otro vistazo a la tienda SQLite como lo hicimos anteriormente.

7. Eliminar registros

Eliminar un registro sigue el mismo patrón que crear y actualizar registros. Le decimos al contexto del objeto administrado que un registro debe eliminarse del almacén persistente invocando deleteObject: y pasando el objeto administrado que debe eliminarse.

En nuestro proyecto, elimine el objeto de persona que obtuvimos anteriormente pasándolo al método deleteObject: del objeto administrado. Tenga en cuenta que la operación de eliminación no se confirma en el almacén de respaldo hasta que llamemos save: en el contexto del objeto administrado.

Conclusión

En este tutorial, hemos cubierto mucho más que solo crear, recuperar, actualizar y eliminar registros. Hemos tocado algunos conceptos importantes en los que se basan los datos básicos, como la compatibilidad de fallas y el modelo de datos.

En la próxima entrega de esta serie, aprenderá cómo crear y actualizar relaciones, y analizaremos en profundidad la clase NSFetchRequest. También comenzaremos a usar NSPredicate y NSSortDescriptor para hacer que nuestras solicitudes de recuperación sean flexibles, dinámicas y potentes.

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.