¿Qué es una falla de datos básicos?

Las fallas son un componente esencial de los datos básicos. A pesar de que el término suena ominoso, las fallas son inherentes al ciclo de vida de un registro de Datos Básicos. En este tutorial, aprenderá qué fallas, cómo manejarlas y cómo depurar problemas relacionados con fallas.

Prerrequisitos

Core Data es un tema avanzado, así que voy a suponer que ya está familiarizado con Xcode y el desarrollo de iOS. Aunque utilizaré el lenguaje de programación Swift para este tutorial, todo en este tutorial también es aplicable a Objective-C.

Wat es un fallo?

Core Data es muy bueno en lo que hace gracias al arduo trabajo del equipo Core Data de Apple. Core Data está altamente optimizado para mantener su espacio de memoria bajo sin sacrificar el rendimiento. La falla es una de las técnicas que usa Core Data para consumir la menor cantidad de memoria posible.

La falla no es exclusiva de los Datos Básicos. Una técnica similar se utiliza en muchos otros marcos, como Ember y Ruby on Rails. La idea es simple, solo cargar datos cuando sea necesario. Para hacer que el trabajo de fallar, Core Data haga un poco de magia bajo el capó creando subclases personalizadas en el momento de la compilación que representan las fallas. Veamos cómo funciona esto con un ejemplo..

He creado una aplicación de ejemplo simple para trabajar. Descargue el proyecto Xcode de GitHub y ábralo en Xcode. El proyecto utiliza Swift 2.1, lo que significa que necesita Xcode 7.1 o superior para satisfacer al compilador.

El modelo de datos contiene dos entidades., Listaít. Una lista puede tener cero o más elementos y un elemento siempre está vinculado a una lista. Es un ejemplo clásico de una relación de uno a muchos..

Ejecute la aplicación y complete el almacén persistente, una base de datos SQLite, con algunos datos mediante la creación de algunas listas y elementos. Salga de la aplicación cuando haya terminado.

Fallas de fuego

Ahora debería tener una aplicación con algunos datos. Veamos cómo funcionan las fallas en la práctica agregando algunas declaraciones impresas. Abierto ListsViewController.swift y buscar prepareForSegue (_: remitente :). En este método, recuperamos la lista que el usuario ha seleccionado en la vista de tabla. Descomentar las declaraciones impresas en prepareForSegue (_: remitente :) como se muestra en la implementación a continuación.

override func prepareForSegue (segue: UIStoryboardSegue, sender: ¿Cualquier objeto?) Imprima la lista ("1: \ (lista)") si deja items = list.items print ("2: \ (items)") print ("3: \ (items.count)") print ("4: \ (elementos) ") si se permite item = items.anyObject () print (" 5: \ (item) ") print (" 6: \ (item.name) ") print (" 7: \ (item) ")  print ("8: \ (list)") // Fetch Destination View Controller permite que listViewController = segue.destinationViewController as! ListViewController // Configurar View Controller listViewController.list = list

Ejecute la aplicación y toque una de las listas en el controlador de vista de listas. El ejemplo solo es interesante si toca una lista que tiene uno o más elementos asociados. Vamos a inspeccionar la salida de las declaraciones de impresión paso a paso.

1:  (entidad: Lista; id: 0xd0000000001c0000  ; datos: items = ""; name =" List 6 ";)

Lo primero a tener en cuenta es el nombre de la clase, Faulting.List. Esto es lo que esperamos ya que el módulo se llama Culpable y la clase se llama Lista. En Swift, el nombre completo de la clase de una clase se compone del nombre del módulo y el nombre de la clase.

La salida en la consola también muestra el nombre de la entidad., Lista, y un diccionario de datos. los nombre atributo se establece en Lista 6 mientras que la artículos atributo está marcado como falla de relación. Este es el primer tipo de falla en Core Data. Core Data entiende que no hay necesidad de cargar la relación. En su lugar, marca la relación como una falta. La segunda declaración impresa confirma esto como se puede ver a continuación.

2: Error de 'elementos' de relación en el objeto administrado (0x154e5d0b0)  (entidad: Lista; id: 0xd0000000001c0000  ; datos: items = ""; name =" List 6 ";)

La tercera declaración impresa, sin embargo, es más interesante. Imprime el número de elementos asociados a la lista..

3: 2

Core Data solo puede hacer esto disparando la falla de la relación. Solicita al almacén persistente los elementos asociados con la lista. Esto, sin embargo, es solo una parte de la historia, como lo ilustra la cuarta declaración impresa..

4: 'Elementos' de relación en el objeto gestionado (0x154e5d0b0)  (entidad: Lista; id: 0xd0000000001c0000  ; datos: elementos = ("0xd000000000540002 "," 0xd000000000580002 "); nombre =" Lista 6 ";) con objetos (  (entidad: artículo; id: 0xd000000000540002  ; datos: ),  (entidad: artículo; id: 0xd000000000580002  ; datos: ))

Ya no vemos una falla en la relación, pero aún vemos una falla. ¿De qué se trata? Los Datos Básicos solo pueden darnos el número de elementos para la lista activando o resolviendo la falla de la relación. Sin embargo, esto no significa que Core Data resuelva los elementos de la relación. La salida en la consola lo confirma..

Podemos ver que los registros de los elementos están allí, incluido el identificador que usa Core Data internamente. El diccionario de datos, sin embargo, está marcado como un fallo. Una vez más, Core Data solo nos da lo que pedimos. Afortunadamente, los datos esenciales están manejados por Core Data.

Vamos a profundizar un poco más y buscar uno de los elementos de la lista. Hacemos esto llamando anyObject () sobre el artículos objeto. Imprimimos el artículo resultante en la quinta declaración impresa..

5:  (entidad: artículo; id: 0xd000000000540002  ; datos: )

La salida no debería sorprenderte. La salida confirma que estamos tratando con un ít entidad. Como era de esperar, el diccionario de datos todavía está marcado como un error. En la sexta declaración impresa, imprimimos el nombre atributo del artículo.

6: Item 0

Debido a que pedimos el valor de un atributo del registro, Core Data dispara la falla para darnos ese valor. Obtiene los datos para el elemento y rellena el diccionario de datos. La séptima declaración impresa confirma estos hallazgos..

7:  (entidad: artículo; id: 0xd000000000540002  ; datos: list = "0xd0000000001c0000 "; name =" Item 0 ";)

El diccionario de datos contiene el nombre atributo, así como la lista relación. La octava y última declaración impresa muestra que la relación falla de la lista el objeto se resuelve.

8:  (entidad: Lista; id: 0xd0000000001c0000  ; datos: elementos = ("0xd000000000540002 "," 0xd000000000580002 "); nombre =" Lista 6 ";)

Incapaz de cumplir una falta

Decidí escribir este artículo para explicar un problema con el que muchos desarrolladores de Core Data se encuentran en un momento u otro, lo que provoca un error que no se puede cumplir. El problema es simple. Supongamos que tiene una lista con varios elementos y, en algún momento, el usuario borra la lista. ¿Qué pasa con los elementos de esa lista? ¿Qué pasa si Core Data intenta disparar el lista ¿Relación de uno de los artículos que pertenecían a esa lista? Vamos a averiguar.

Vamos a revisar el proyecto que has descargado de GitHub. Abierto Faulting.xcdatamodeld, El modelo de datos del proyecto. Selecciona el artículos relación de la Lista entidad y abrir el Inspector de modelo de datos a la derecha. Lo que nos interesa es el Eliminar regla, que actualmente está configurado para cascada. Esto significa que todos los elementos de la lista se eliminan cuando se elimina la lista. Esto tiene sentido ya que no queremos tener elementos abandonados que no están asociados con una lista.

Selecciona el lista relación de la ít entidad y abrir el Inspector de modelo de datos. los Eliminar regla de esta relación se establece en Anular. Esto significa que el destino de la relación, el objeto de la lista, se establece en nulo cuando el registro de destino, el elemento, se elimina. Esta es la regla de eliminación predeterminada para una relación.

Ejecute la aplicación, cree algunas listas y elementos, y toque el Artículos botón en la parte superior izquierda para mostrar cada elemento que ha creado. Grifo Cancelar en la parte superior izquierda, elimine una de las listas y toque Artículos botón de nuevo para ver lo que ha cambiado. Como se esperaba, los elementos asociados con la lista eliminada también se han eliminado con Core Data. Esto no es magia. Los datos básicos simplemente ejecutan las reglas de eliminación que definimos en el modelo de datos.

Podemos concluir que las relaciones están configuradas correctamente para este tipo de aplicación. Pero que pasa si no configuramos las reglas de borrado correctamente. Abra el modelo de datos y establezca la regla de eliminación de ambas relaciones., artículoslista, a Ninguna acción. Vuelva a iniciar la aplicación y cree algunas listas y elementos. Si borras una lista y tocas Artículos botón en la parte superior izquierda para ver todos los elementos en el almacén persistente, los elementos asociados con la lista eliminada aún deben estar allí. No se eliminaron a pesar de que la lista a la que pertenecen ha sido eliminada.

Toque una de las listas y vea qué sucede. Si está ejecutando la aplicación en iOS 8, la aplicación se bloqueará debido a una excepción no detectada. Si está ejecutando la aplicación en iOS 9, solo verá un error en la consola. Deja de rascarte la cabeza y vamos a resolver esto juntos.

Objeto inaccesible

A pesar de que la aplicación falla en iOS 8, la salida que vemos en la consola es clara y al punto.

Error [7189: 2427906] *** Se cerró la aplicación debido a una excepción no detectada 'NSObjectInaccessibleException', motivo: 'CoreData no pudo cumplir un error para' 0x175b2ba0 "

Lo primero que debe notar es que la aplicación se bloqueó debido a una excepción no detectada. Lo que es más importante para nuestra discusión, sin embargo, es la razón por la que se lanzó la excepción. Core Data nos dice que no pudo cumplir una falla en una relación. La relación a la que se refieren los Datos Básicos es la lista Relación del elemento que pulsamos en la vista de tabla..

Si nos fijamos en la implementación de tableView (tableView: didSelectRowAtIndexPath :), entonces entenderás por qué Core Data lanzó una excepción. En este método, recuperamos el elemento que el usuario tocó e imprimimos el nombre de la lista en la consola.

func tableView (tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) tableView.deselectRowAtIndexPath (indexPath, animated: true) si let item = self.fetchedResultsController.objectAtIndexPath (indexPath) como? Artículo print (item.list? .Name)

Porque el lista la relación es una falla, Core Data necesita disparar la falla para resolverla. Esto significa que Core Data solicita al almacén persistente el registro de la lista. El problema es que el registro ya no está en el almacén persistente, por lo que se lanzó una excepción.

Eliminar fallas inaccesibles

Hasta iOS 9, este siempre ha sido el comportamiento por defecto. A partir de iOS 9, Core Data ya no lanza una excepción. En su lugar, registra un mensaje críptico en la consola. A pesar de que el mensaje no está claro, todavía contiene la razón del problema.

Error [2806: 1306995] CoreData: advertencia: un delegado NSManagedObjectContext anula el comportamiento de manejo de errores para eliminar silenciosamente el objeto con ID '0xd000000000140000 'y sustituye nil / 0 por todos los valores de propiedad en lugar de lanzar.

Lo esencial es que Core Data ya no lanza una excepción cuando no puede cumplir una falla. La buena noticia es que su aplicación ya no se bloquea si no detecta la excepción.

La razón para no lanzar una excepción en iOS 9 se debe a la introducción de una nueva propiedad, shouldDeleteInaccessibleFaults, y un nuevo método, shouldHandleInaccessibleFault (_: forObjectID: triggeredByProperty :), sobre el NSManagedObjectContext clase. No cubriré estas adiciones en este tutorial..

Lo que debe recordar es que iOS 9, de forma predeterminada, establece el shouldDeleteInaccessibleFaults a cierto. Esto significa que un objeto administrado inaccesible se marca como eliminado y sus propiedades se ponen a cero. Si shouldDeleteInaccessibleFaults se establece en falso, Los datos básicos vuelven al comportamiento anterior al lanzar una excepción.

Por supuesto, el shouldDeleteInaccessibleFaults la propiedad va de la mano con shouldHandleInaccessibleFault (_: forObjectID: triggeredByProperty :). Si anula este método, puede manejar objetos inaccesibles de manera más elegante.

Manejo de fallas

Cuando encuentra una excepción debido a que Core Data no puede cumplir una falla, puede pensar que Core Data está siendo un poco agresivo. Esta reacción es bastante común para las personas nuevas en el marco. La verdad es que el desarrollador tiene la culpa. Los datos básicos se diseñaron teniendo en cuenta un conjunto específico de objetivos y las fallas son un componente esencial para alcanzar estos objetivos..

A pesar de su nombre, las fallas siempre deben ser cumplidas. Si no se puede resolver un error, eso significa que el modelo de datos no está configurado correctamente o que la aplicación no respeta las reglas establecidas por el marco de Core Data.

En la Guía de programación de datos básicos, Apple enumera una serie de escenarios que pueden llevar a fallas que ya no se pueden cumplir. Los escenarios más comunes son las relaciones configuradas incorrectamente (eliminar reglas) y eliminar un objeto administrado mientras la aplicación aún tiene una referencia sólida a ese objeto administrado.

Se advierte, hay otros escenarios posibles. Desde mi experiencia, los desarrolladores a menudo se encuentran con problemas similares debido a un problema con la pila de Datos Core. Por ejemplo, si la aplicación mantiene una fuerte referencia a un objeto administrado y, en algún momento, desasigna el contexto del objeto administrado de ese objeto administrado, entonces Core Data ya no puede cumplir ningún error para ese objeto administrado. Espero que entiendas que esto no debería suceder si juegas según las reglas de Core Data..

Conclusión

Los errores de Core Data son increíblemente útiles y son un componente clave del marco de persistencia de Apple. Espero que este artículo le haya enseñado cómo lidiar con las fallas y dónde buscarlas si encuentra fallas que no se pueden cumplir. Si tiene alguna pregunta, no dude en dejarla en los comentarios a continuación o comuníquese conmigo en Twitter..