objective hacer consumir consume iphone objective-c rest core-data

iphone - consumir - hacer un login en swift



Cómo sincronizar CoreData y un servicio web REST de forma asíncrona y al mismo tiempo propagar correctamente cualquier error REST en la interfaz de usuario (4)

Oye, estoy trabajando en la capa de modelo para nuestra aplicación aquí.

Algunos de los requisitos son así:

  1. Debería funcionar en iPhone OS 3.0+.
  2. La fuente de nuestros datos es una aplicación RESTful Rails.
  3. Deberíamos almacenar en caché los datos localmente utilizando Core Data.
  4. El código del cliente (nuestros controladores de interfaz de usuario) debe tener tan poco conocimiento sobre cualquier material de red como sea posible y debe consultar / actualizar el modelo con la API de datos principales.

Revisé la sesión 117 de la WWDC10 sobre Cómo crear una experiencia de usuario basada en el servidor, dediqué un tiempo a revisar los marcos de Recursos de objetivos , Recursos básicos y RestfulCoreData .

El marco de recursos objetivos no se comunica con Core Data por sí solo y no es más que una implementación de cliente REST. The Core Resource y RestfulCoreData suponen que hablas con Core Data en tu código y resuelven todos los aspectos prácticos del fondo en la capa del modelo.

Todo se ve bien hasta ahora e inicialmente pensé que Core Resource o RestfulCoreData cubrirían todos los requisitos anteriores, pero ... Hay un par de cosas que aparentemente ninguna de ellas resuelve correctamente:

  1. El hilo principal no se debe bloquear mientras se guardan las actualizaciones locales en el servidor.
  2. Si la operación de salvar falla, el error debe propagarse a la UI y no se deben guardar cambios en el almacenamiento local de datos centrales.

Core Resource pasa a emitir todas sus solicitudes al servidor cuando usted llama - (BOOL)save:(NSError **)error en su Contexto de Objeto Administrado y, por lo tanto, puede proporcionar una instancia NSError correcta de las solicitudes subyacentes al servidor. de algun modo. Pero bloquea el hilo de llamada hasta que finaliza la operación de salvar. FALLAR.

RestfulCoreData mantiene sus llamadas -save: intactas y no introduce ningún tiempo de espera adicional para el hilo del cliente. Simplemente vigila el NSManagedObjectContextDidSaveNotification y luego emite las solicitudes correspondientes al servidor en el controlador de notificaciones. Pero de esta forma la llamada a- -save: siempre se completa con éxito (bueno, dado que Core Data está bien con los cambios guardados) y el código del cliente que realmente lo llamó no tiene forma de saber que la operación de guardado no pudo propagarse al servidor debido a algunos 404 o 421 o cualquier error del lado del servidor ocurrido. Y aún más, el almacenamiento local pasa a tener los datos actualizados, pero el servidor nunca sabe de los cambios. FALLAR.

Entonces, estoy buscando una posible solución / prácticas comunes para enfrentar todos estos problemas:

  1. No quiero que el hilo que llama se bloquee en cada llamada a " -save: mientras se producen las solicitudes de red.
  2. De alguna manera, quiero recibir notificaciones en la UI de que alguna operación de sincronización salió mal.
  3. Quiero que el almacenamiento de datos básicos real también falle si las solicitudes del servidor fallan.

¿Algunas ideas?


Deberías echarle un vistazo a RestKit ( http://restkit.org ) para este caso de uso. Está diseñado para resolver los problemas de modelado y sincronización de recursos JSON remotos a un caché respaldado por Core Data local. Admite un modo fuera de línea para trabajar completamente desde la memoria caché cuando no hay una red disponible. Toda la sincronización se produce en un hilo de fondo (acceso a la red, análisis de carga útil y fusión de contexto de objetos administrados) y hay un amplio conjunto de métodos de delegado para que pueda ver qué está sucediendo.


Esto se convierte en un problema de sincronización y no es fácil de resolver. Esto es lo que haría: en la interfaz de usuario de su iPhone use un contexto y luego use otro contexto (y otro hilo) para descargar los datos de su servicio web. Una vez que todo esté listo, realice los procesos de sincronización / importación recomendados a continuación y luego actualice su UI después de que todo se haya importado correctamente. Si las cosas van mal mientras se accede a la red, simplemente deshaga los cambios en el contexto no UI. Es un montón de trabajo, pero creo que es la mejor manera de abordarlo.

Datos principales: importación eficiente de datos

Datos principales: gestión del cambio

Datos principales: Multi-Threading con Core Data


Hay tres componentes básicos:

  1. La acción de IU y persistir en el cambio a CoreData
  2. Persistiendo que cambien al servidor
  3. Actualizar la interfaz de usuario con la respuesta del servidor

Un NSOperation + NSOperationQueue ayudará a mantener ordenadas las solicitudes de red. Un protocolo de delegado ayudará a sus clases de IU a comprender en qué estado se encuentran las solicitudes de red, algo así como:

@protocol NetworkOperationDelegate - (void)operation:(NSOperation *)op willSendRequest:(NSURLRequest *)request forChangedEntityWithId:(NSManagedObjectID *)entity; - (void)operation:(NSOperation *)op didSuccessfullySendRequest:(NSURLRequest *)request forChangedEntityWithId:(NSManagedObjectID *)entity; - (void)operation:(NSOperation *)op encounteredAnError:(NSError *)error afterSendingRequest:(NSURLRequest *)request forChangedEntityWithId:(NSManagedObjectID *)entity; @end

El formato de protocolo dependerá, por supuesto, de su caso de uso específico, pero esencialmente lo que está creando es un mecanismo mediante el cual los cambios pueden ser "empujados" hacia su servidor.

Luego, hay que considerar el ciclo UI, para mantener el código limpio, sería bueno llamar a guardar: y hacer que los cambios se transfieran automáticamente al servidor. Puede usar notificaciones de NSManagedObjectContextDidSave para esto.

- (void)managedObjectContextDidSave:(NSNotification *)saveNotification { NSArray *inserted = [[saveNotification userInfo] valueForKey:NSInsertedObjects]; for (NSManagedObject *obj in inserted) { //create a new NSOperation for this entity which will invoke the appropraite rest api //add to operation queue } //do the same thing for deleted and updated objects }

La sobrecarga computacional para insertar las operaciones de la red debería ser bastante baja; sin embargo, si crea un retraso notable en la UI, simplemente podría extraer los ID de la entidad de la notificación de guardado y crear las operaciones en una cadena de fondo.

Si su API REST admite lotes, incluso podría enviar toda la matriz a la vez y luego notificar a la IU que se sincronizaron varias entidades.

El único problema que preveo, y para el cual no hay una solución "real" es que el usuario no quiera esperar a que sus cambios sean enviados al servidor para poder hacer más cambios. El único paradigma bueno que he encontrado es que le permite al usuario seguir editando objetos, y agrupar sus ediciones juntos cuando corresponde, es decir, no presiona cada notificación de guardado.


Necesita una función de devolución de llamada que se ejecutará en el otro subproceso (aquella donde ocurre la interacción real del servidor) y luego coloque el código de resultado / información de error en un dato semi-global que será verificado periódicamente por el subproceso de la interfaz de usuario. Asegúrate de que la escritura del número que sirve como bandera sea atómica o de que tengas una condición de carrera; por ejemplo, si tu respuesta de error es de 32 bytes, necesitas una int (que debería tener acceso atómico) y luego mantienes esa int en el estado apagado / falso / no listo hasta que se haya escrito su bloque de datos más grande y solo luego escriba "verdadero" para activar el interruptor por así decirlo.

Para el guardado correlacionado en el lado del cliente, tiene que guardar esos datos y no guardarlos hasta que consiga el permiso del servidor de asegurarse de tener una opción de reversión: digamos que una forma de eliminar es la falla del servidor.

Tenga en cuenta que nunca va a ser 100% seguro a menos que realice un procedimiento de confirmación de dos fases completo (el cliente puede guardar o eliminar puede fallar después de la señal del servidor) pero eso le costará 2 viajes al servidor como mínimo ( le puede costar 4 si su única opción de reversión es eliminar).

Idealmente, harías toda la versión de bloqueo de la operación en un hilo separado, pero necesitarías 4.0 para eso.