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

Construir una aplicación de lista de compras con CloudKit: Agregar relaciones

by
Difficulty:IntermediateLength:LongLanguages:
This post is part of a series called Building a Shopping List Application With CloudKit.
Building a Shopping List Application With CloudKit: Adding Records
Building a Shopping List Application With CloudKit: Sharing Shopping Items

Spanish (Español) translation by CYC (you can also view the original English article)

En el tutorial anterior de esta serie, incluimos la posibilidad de agregar, actualizar y eliminar listas de compras. Sin embargo, una lista de compras sin ningún artículo no es muy útil. En este tutorial, agregaremos la capacidad de agregar, actualizar y eliminar elementos de una lista de compras. Esto significa que trabajaremos con referencias y la clase CKReference.

También veremos más de cerca el modelo de datos de la aplicación de la lista de compras. ¿Qué tan fácil es hacer cambios en el modelo de datos y cómo responde la aplicación a los cambios que hacemos en CloudKit Dashboard?

Requisitos previos

Recuerda que usaré Xcode 7 y Swift 2. Si estás usando una versión anterior de Xcode, ten en cuenta que estás usando una versión diferente del lenguaje de programación Swift.

En este tutorial, continuaremos donde lo dejamos en el segundo tutorial de esta serie. Puedes descargar o clonar el proyecto desde GitHub.

1. Detalles de la lista de compras

Actualmente, el usuario puede modificar el nombre de una lista de compras tocando el indicador de divulgación de detalles, pero el usuario también debe poder ver el contenido de una lista de compras tocando uno en el controlador de vista de listas. Para que esto funcione, primero necesitamos una nueva subclase UIViewController.

Paso 1: Crear el ListViewController

La clase ListViewController mostrará el contenido de una lista de compras en una vista de tabla. La interfaz de la clase ListViewController es similar a la de la clase ListsViewController. Importamos los frameworks CloudKit y SVProgressHUD y conformamos la clase a los protocolos UITableViewDataSource y UITableViewDelegate. Debido a que utilizaremos una vista de tabla, declaramos una constante, ItemCell, que servirá como un identificador de reutilización de celda.

Declaramos tres puntos de venta, messageLabel del tipo UILabel!, tableView del tipo UITableView! Y activityIndicatorView del tipo UIActivityIndicatorView!. El controlador de vista de lista mantiene una referencia a la lista de compras que se muestra en la propiedad list, que es de tipo CKRecord!. Los elementos de la lista de compras se almacenan en la propiedad items, que es del tipo [CKRecord]. Finalmente, utilizamos una variable auxiliar, selection, para realizar un seguimiento de qué elemento en la lista de compras ha seleccionado el usuario. Esto quedará claro más adelante en este tutorial.

Paso 2: Creando una interfaz de usuario

Abre Main.storyboard, agrega un controlador de vista y establece su clase en ListViewController en el Inspector de identidad. Selecciona la celda del prototipo del controlador de vista de listas, presiona la tecla de control y arrastra desde la celda de prototipo al controlador de vista de lista. Elige Mostrar en el menú que aparece y establece el identificador en la Lista en el Inspector de Atributos.

Agrega una vista de tabla, una etiqueta y una vista de indicador de actividad a la vista del controlador de vista. No olvides conectar las salidas del controlador de visualización así como las de la vista de tabla.

Selecciona la vista de tabla y configura las Celdas de prototipo en 1 en el Inspector de atributos. Selecciona la celda del prototipo, establece Style en Right Detail, Indentifier en ItemCell y Accessory en Disclosure Indicator. Este es el aspecto que debería tener el controlador de vista cuando hayas terminado.

List View Controller

Paso 3: Configurando el Controlador de Vista

Antes de volver a visitar el framework de CloudKit, debemos preparar el controlador de vista para los datos que va a recibir. Comienza por actualizar la implementación de viewDidLoad. Establecemos el título del controlador de vista en el nombre de la lista de compras e invocamos dos métodos auxiliares, setupView y fetchItems.

El método setupView es idéntico al que implementamos en la clase ListsViewController.

Mientras estamos en ello, implementemos también otro método familiar de ayuda, updateView. En updateView, actualizamos la interfaz de usuario del controlador de vista en función de los elementos almacenados en la propiedad de los elementos.

Voy a dejar a fetchItems vacío por ahora. Volveremos a visitar este método una vez que hayamos terminado de configurar el controlador de vista de lista.

Paso 4: Métodos de fuente de datos de vista de tabla

Estamos casi listos para tomar la aplicación para otra prueba. Antes de hacerlo, debemos implementar el protocolo UITableViewDataSource. Si has leído las entregas anteriores de esta serie, la implementación te resultará familiar.

Paso 5: Manejando la selección

Para unir todo, necesitamos volver a visitar la clase ListsViewController. Comienza implementando el método tableView (_:didSelectRowAtIndexPath:) del protocolo UITableViewDelegate.

También necesitamos actualizar prepareForSegue (segue:sender:) para manejar el segue que creamos hace unos momentos. Esto significa que necesitamos agregar un nuevo case a la declaración de switch.

Para satisfacer al compilador, también debemos declarar la constante SegueList en la parte superior de ListsViewController.swift.

Crea y ejecuta la aplicación para ver si todo está conectado correctamente. Debido a que aún no hemos implementado el método fetchItems, no se mostrarán elementos. Eso es algo que tenemos que arreglar.

2. Obteniendo los artículos

Paso 1: Crear el tipo de registro

Antes de que podamos obtener elementos del backend de CloudKit, debemos crear un nuevo tipo de registro en el CloudKit Dashboard. Navega hacia el Dashboard de CloudKit, crea un nuevo tipo de registro y asígnale el nombre Items. Cada elemento debe tener un nombre, por lo tanto, crea un nuevo campo, establece el nombre del campo en name y establece el tipo de campo en String.

Cada artículo también debe saber a qué lista de compras pertenece. Eso significa que cada artículo necesita una referencia a su lista de compras. Crea un nuevo campo, establece el nombre del campo en list y establece el tipo de campo como Reference. El tipo de campo Reference fue diseñado para este propósito exacto, administrando relaciones.

Item Record Type

Regresa a Xcode, abre Lists ViewController.swift y declara una nueva constante en la parte superior para el tipo de registro de Items.

Paso 2: Recuperar elementos

Abre ListViewController.swift y navega hasta el método fetchItems. La implementación es similar al método fetchLists de la clase ListsViewController. Sin embargo, hay una diferencia importante.

La diferencia entre fetchItems y fetchLists es el predicado que pasamos al inicializador CKQuery. No estamos interesados en cada elemento en la base de datos privada del usuario. Solo estamos interesados en los artículos que están asociados con una lista de compras en particular. Esto se refleja en el predicado de la instancia CKQuery.

Creamos el predicado pasando una instancia CKReference, que creamos invocando init (recordID:action:). Este método acepta dos argumentos, una instancia de CKRecordID que hace referencia al registro de la lista de compras y una instancia de CKReferenceAction que determina lo que sucede cuando se elimina la lista de compras.

Las acciones de referencia son muy similares a las reglas de eliminación en Core Data. Si el objeto al que se hace referencia, la lista de compras en este ejemplo, se elimina, entonces el framework CloudKit inspecciona la acción de referencia para determinar qué debería pasar con los registros que contienen una referencia al registro eliminado. La enumeración CKReferenceAction tiene dos valores de miembro:

  • None: Si se elimina la referencia, no ocurre nada con los registros que hacen referencia al registro eliminado.
  • DeleteSelf: Si se elimina la referencia, también se elimina cada registro que hace referencia al registro eliminado.

Debido a que no debe existir ningún artículo sin una lista de compras, establecemos la acción de referencia en DeleteSelf.

El método processResponseForQuery(records:) no contiene nada nuevo. Procesamos la respuesta de la consulta y actualizamos la interfaz de usuario en consecuencia.

Compila y ejecuta la aplicación. Aún no verás ningún elemento, pero la interfaz de usuario se debería actualizar para reflejar que la lista de compras está vacía.

3. Agregar elementos

Paso 1: Crear el AddItemViewControler

Es hora de implementar la capacidad de agregar elementos a una lista de compras. Comienza creando una nueva subclase UIViewController, AddItemViewController. La interfaz del controlador de vista es similar a la de la clase AddListViewController.

En la parte superior, importamos los frameworks CloudKit y SVProgressHUD. Declaramos el protocolo AddItemViewControllerDelegate, que servirá para el mismo propósito que el protocolo AddListViewControllerDelegate. El protocolo define dos métodos, uno para agregar elementos y otro para actualizar elementos.

Declaramos dos puntos de salida, un campo de texto y un elemento de botón de barra. También declaramos una propiedad para el delegado y una variable auxiliar, newItem, que nos ayuda a determinar si estamos creando un nuevo elemento o actualizando un elemento existente. Finalmente, declaramos una lista de propiedades para hacer referencia a la lista de compras a la que se agregará el artículo y un elemento de propiedad para el item que estamos creando o actualizando.

Antes de crear la interfaz de usuario, implementemos dos acciones que necesitaremos en el storyboard, cancel(_:) y save(_:). Actualizaremos la implementación de la acción save(_:) más adelante en este tutorial.

Paso 2: Crear una interfaz de usuario

Abre Main.storyboard, agrega un elemento de botón de barra a la barra de navegación del controlador de vista de lista, y configura el elemento del sistema para agregarlo en el Inspector de atributos. Arrastra un controlador de vista desde la Biblioteca de objetos y establece su clase en AddItemViewController. Crea un segue desde el elemento del botón de barra que acabamos de crear para agregar el control de vista del elemento. Elige Mostrar en el menú que aparece y establece el identificador del segue en ItemDetail.

Agrega dos elementos de botón de barra a la barra de navegación del controlador de vista de agregar elemento, un botón de cancelar a la izquierda y un botón de guardar a la derecha. Conecta cada elemento del botón de la barra a su acción correspondiente. Agrega un campo de texto a la vista del controlador de vista y no olvides conectar las salidas del controlador de vista. Este es el aspecto que debería tener el controlador de vista de elementos agregados cuando hayas terminado.

Add Item View Controller

Paso 3: Configurando el Controlador de Vista

La implementación del controlador de vista para agregar el elemento no contiene nada que aún no hayamos cubierto. Sin embargo, hay una excepción, que discutiremos en un momento. Comencemos configurando el controlador de vista en viewDidLoad.

Invocamos setupView, un método de ayuda, y actualizamos el valor de newItem. Si la propiedad del item es igual a nil, newItem es igual a true. Esto nos ayuda a determinar si estamos creando o actualizando un elemento de la lista de compras.

También agregamos el controlador de vista como un observador para las notificaciones de tipo UITextFieldTextDidChangeNotification. Esto significa que el controlador de vista se notifica cuando el contenido del nameTextField cambia.

En viewDidAppear(animated:), mostramos el teclado llamando a becomeFirstResponder en nameTextField.

El método setupView invoca dos métodos auxiliares, updateNameTextField y updateSaveButton. La implementación de estos métodos auxiliares es sencilla. En updateNameTextField, llenamos el campo de texto. En updateSaveButton, habilitamos o inhabilitamos el botón de guardar en función del contenido del campo de texto.

Antes de echar un vistazo a la implementación actualizada del método save(_:), debemos implementar el método textFieldDidChange(_:). Todo lo que hacemos es invocar updateSaveButton para habilitar o deshabilitar el botón guardar.

Paso 4: Guardar elementos

El método save(_:) es el método más interesante de la clase AddItemViewController, porque nos muestra cómo trabajar con las referencias de CloudKit. Echa un vistazo a la implementación del método save(_:) a continuación.

La mayor parte de su implementación debería ser familiar ya que cubrimos el tema de guardar registros en la clase AddListViewController. Lo que más nos interesa es cómo el artículo mantiene una referencia a su lista de compras. Primero creamos una instancia de CKReference invocando el inicializador designado, init (recordID:action:). Cubrimos los detalles de la creación de una instancia de CKReference hace unos minutos cuando creamos la consulta para obtener elementos de la lista de compras.

Contar el artículo acerca de esta referencia es fácil. Invocamos setObjec(_:forKey:) en la propiedad del item, pasando en la instancia CKReference como el valor y "list" como la clave. La clave se corresponde con el nombre del campo que asignamos en el Dashboard de instrumentos de CloudKit. Guardar el elemento en iCloud es idéntico al que hemos cubierto anteriormente. Así de fácil es trabajar con referencias de CloudKit.

La implementación de processResponse(record:error:) no contiene nada nuevo. Verificamos si apareció algún error y, si no se produjeron errores, se lo notificamos al delegado.

Paso 5: Actualizando el ListViewController

Todavía tenemos trabajo por hacer en la clase ListViewController. Comienza por conformar la clase ListViewController con el protocolo AddItemViewControllerDelegate. Este también es un buen momento para declarar una constante para el segue con el identificador ItemDetail.

Implementar el protocolo AddItemViewControllerDelegate es trivial. En el controlador (_:didAddItem:), agregamos el nuevo elemento a los items, ordenamos los items, volvemos a cargar la vista de tabla e invocamos updateView.

La implementación del controlador (_:didUpdateItem:) es aún más fácil. Ordenamos los items y volvemos a cargar la vista de tabla.

En sortItems, ordenamos la matriz de instancias de CKRecord por nombre utilizando la función sortInPlace, un método del protocolo MutableCollectionType.

Hay dos funciones más que debemos implementar, actualizar y eliminar elementos de la lista de compras.

Paso 6: Eliminar elementos

Para eliminar elementos, debemos implementar tableView(_:commitEditingStyle:forRowAtIndexPath:) del protocolo UITableViewDataSource. Buscamos el elemento de la lista de compras que debe eliminarse y lo pasamos al método deleteRecord(_:).

La implementación de deleteRecord(_:) no contiene nada nuevo. Invocamos deleteRecordWithID(_:completionHandler:) en la base de datos privada y procesamos la respuesta en el controlador de finalización.

En processResponseForDeleteRequest(record:recordID:error:), actualizamos la propiedad de los items y la interfaz de usuario. Si algo salió mal, notificamos al usuario mostrando una alerta.

Paso 7: Actualizar elementos

El usuario puede actualizar un elemento tocando el indicador de divulgación de detalles. Esto significa que debemos implementar el método de delegado tableView(_:accessoryButtonTappedForRowWithIndexPath:). En este método, almacenamos la selección del usuario y realizamos manualmente el segue ListDetail. Ten en cuenta que no ocurre nada en el método tableView(_:didSelectRowAtIndexPath:). Todo lo que hacemos es anular la selección de la fila que tocó el usuario.

En prepareForSegue(_:sender:), buscamos el elemento de la lista de compras utilizando el valor de la propiedad de selection y configuramos el controlador de vista de destino, una instancia de la clase AddItemViewController.

Eso es todo lo que tenemos que hacer para eliminar y actualizar los elementos de la lista de compras. En la siguiente sección, exploramos qué fácil es actualizar el modelo de datos en el Dashboard de CloudKit.

4. Actualización del modelo de datos

Si alguna vez trabajaste con Core Data, entonces sabes que la actualización del modelo de datos se debe hacer con precaución. Debes asegurarte de no romper nada ni dañar ninguno de los almacenes permanentes de la aplicación. CloudKit es un poco más flexible.

El tipo de registro de los items actualmente tiene dos campos, name y list. Quiero mostrarte lo que implica actualizar el modelo de datos agregando un nuevo campo. Abre el Dashboard de CloudKit y agrega un nuevo campo al registro de Items. Establece el nombre del campo en number y establece el tipo de campo en Int(64). No te olvides de guardar tus cambios.

Update Item Record Type

Vamos a añadir ahora la capacidad de modificar el número de un artículo. Abre AddItemViewController.swift y declara dos puntos de venta, una etiqueta y un paso a paso.

También debemos agregar una acción que se active cuando cambie el valor del paso a paso. En numberDidChange(_:), actualizamos los contenidos de numberLabel.

Abre Main.storyboard y agrega una etiqueta y un paso a paso al control de vista de elementos agregados. Conecta las salidas del controlador de vista a los elementos correspondientes de la interfaz de usuario y conecta la acción numberDidChange(_:) al paso a paso para el evento Value Changed.

Update Add Item View Controller

La acción save(_:) de la clase AddItemViewController también cambia ligeramente. Veamos cómo se ve eso.

Solo necesitamos agregar dos líneas de código. A la parte superior, almacenamos el valor del paso a paso en un número constante. Cuando configuramos el item, establecemos el número como el valor de la tecla "number" y eso es todo lo que hay.

También necesitamos implementar un método auxiliar para actualizar la interfaz de usuario del controlador de vista de elementos agregados. El método updateNumberStepper comprueba si el registro tiene un campo llamado number y actualiza el paso a paso si lo hace.

Invocamos updateNumberStepper en el método setupView de la clase AddItemViewController.

Para visualizar el número de cada artículo, debemos hacer un cambio en el ListViewController. En tableView(_:cellForRowAtIndexPath:), establecemos el contenido de la etiqueta derecha de la celda en el valor del campo numérico del elemento.

Eso es todo lo que tenemos que hacer para implementar los cambios que realizamos en el modelo de datos. No es necesario realizar una migración ni nada de eso. CloudKit se ocupa de los detalles esenciales.

Conclusión

Ahora deberías tener una base adecuada del framework CloudKit. Espero que estés de acuerdo con que Apple haya hecho un gran trabajo con el framework y el Dashboad de CloudKit. Hay muchas cosas que no hemos cubierto en esta serie, pero esto debería darte suficiente para comenzar a usar CloudKit en tus propios proyectos.

Si tienes alguna pregunta o comentario, siéntete libre de dejarlos en la sección de comentarios a continuación o comunícate conmigo en Twitter.

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.