Cómo sincronizar datos básicos con un servicio Web && num; 8211 & semi; Parte 2

August 16|8 Vistas|

Resumen: Si eres nuevo aquí, tal vez quieras suscribirte a mi feed RSS o seguirme en Twitter. ¡Gracias por su visita! Aprenda a sincronizar Core Data con un servicio web! Este es un post de iOS Tutorial miembro del equipo Chris Wagner, un entusiasta en la ing

Advertisement

Si eres nuevo aquí, tal vez quieras suscribirte a mi feed RSS o seguirme en Twitter. ¡Gracias por su visita!

Cómo sincronizar datos básicos con un servicio Web && num; 8211 & semi;  Parte 2

Aprenda a sincronizar Core Data con un servicio web!

Este es un post de iOS Tutorial miembro del equipo Chris Wagner, un entusiasta en la ingeniería de software siempre tratando de mantenerse por delante de la curva. También puedes encontrarlo en Google+.

Bienvenido nuevamente a nuestra serie de tutoriales en 2 partes sobre cómo sincronizar datos básicos con un servicio web.

Sólo para refrescar tu memoria, esto es lo que hiciste en la primera parte de esta serie:

  1. Descargado y ejecutado el proyecto de arranque
  2. Configurar una cuenta Parse gratuita
  3. Escrito un cliente de AFNetworking para hablar con el Parse REST API
  4. Creó una clase Singleton "Sync Engine" para manejar la sincronización
  5. Datos de servicios web procesados ​​en Core Data
  6. Sincronización manual con servicio remoto

El resultado neto de todo ese duro trabajo anterior fue que terminó con una aplicación que registra fechas importantes y sincroniza esos datos con el servicio de almacenamiento en línea. Si bien es increíblemente genial, puede hacer que la aplicación aún más impresionante por completar esta segunda parte y final de la serie!

Aquí completarás tres piezas más vitales para completar tu aplicación:

  1. Eliminar objetos locales cuando se eliminan en el servidor
  2. Empujar los registros creados localmente a servicio remoto
  3. Eliminar registros en el servidor cuando se elimina localmente

Si no completó la parte 1, perdió su proyecto, o simplemente desea iniciar el tutorial sabiendo que su código está en sincronía, ¡no te preocupes! :] Puede descargar todo lo que se describe en la Parte 1 aquí.

Si decide utilizar este archivo, asegúrese de reemplazar los valores de kSDFParseAPIApplicationId y kSDFParseAPIKey por los valores proporcionados desde la pestaña Resumen de la ventana Parse project. Además, asegúrese de crear y ejecutar el programa antes de ir más lejos sólo para asegurarse de que todo está en buen estado de funcionamiento.

Listo? Vamos a sumergirnos en la eliminación!

Eliminar objetos locales cuando se eliminan en el servidor

Para asegurarse de que los objetos locales se eliminan cuando ya no existen en el servidor, la aplicación descargará todos los registros del servidor y los comparará con lo que tiene localmente. Se supone que cualquier registro que tenga localmente, que no existe en el servidor, debe ser eliminado.

Un efecto secundario no deseado con la API Parse REST es que este enfoque provoca una sobrecarga mientras recupera los objetos completos, en lugar de sólo los campos objectID. (Uso de datos sagrados, Batman!) Alternativamente, podría tener un indicador de eliminación en sus registros en el servicio remoto y recuperar todos los registros que coincidan con el conjunto de flag eliminado. Mientras que este acercamiento reduciría gastos indirectos, la desventaja es que usted puede nunca realmente suprimir registros del servidor - los expedientes se pegarán alrededor en perpetuidad.

Primero, en SDSyncEngine.m, actualice la firma de:

  - (void) downloadDataForRegisteredObjects: (BOOL) useUpdatedAtDate { 

Ser:

  - (void) downloadDataForRegisteredObjects: (BOOL) useUpdatedAtDate toDeleteLocalRecords: (BOOL) toDelete { 

Y luego actualice su método -startSync para reflejar la nueva firma:

  - (void) startSync {if (! Self.syncInProgress) {[self willChangeValueForKey: @ "syncInProgress"];  _syncInProgress = SI;  [Self didChangeValueForKey: @ "syncInProgress"];  Dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^ {[auto downloadDataForRegisteredObjects: YES toDeleteLocalRecords: NO];});  }} 

Ahora necesita un método para procesar la eliminación de estos registros locales. Agregue el siguiente método a continuación -processJSONDataRecordsIntoCoreData:

  - (void) processJSONDataRecordsForDeletion {NSManagedObjectContext * managedObjectContext = [[SDCoreDataController sharedInstance] backgroundManagedObjectContext];  // // Iterate sobre todas las clases registradas para sincronizar // for (NSString * className en self.registeredClassesToSync) {// // Recuperar los registros de respuesta JSON del disco // NSArray * JSONRecords = [auto JSONDataRecordsForClass: className sortedByKey: @ " ObjectId "];  If ([JSONRecords count]> 0) {// // Si hay registros que buscan todos los registros almacenados localmente que NO están en la lista de registros descargados // NSArray * storedRecords = [self managedObjectsForClass: className sortedByKey: @ "objectId" UsingArrayOfIds: [JSONRecords valueForKey: @ "objectId"] inArrayOfIds: NO];  // // Programar NSManagedObject para borrar y guardar el contexto // [managedObjectContext performBlockAndWait: ^ {for (NSManagedObject * managedObject en storedRecords) {[managedObjectContext deleteObject: managedObject];  } NSError * error = nil;  BOOL saved = [managedObjectContext save: & error];  If (! Saved) {NSLog (@ "No se puede guardar el contexto después de eliminar registros para la clase% @ because% @", className, error);  }}];  } // // Elimina todos los archivos de respuesta de JSON Record para limpiarlos después de ti // [self deleteJSONDataRecordsForClassWithName: className];  } // // Ejecuta las operaciones de finalización de sincronización ya que este es ahora el último paso del proceso de sincronización // [self executeSyncCompletedOperations];  } 

A continuación, actualizar la implementación de -downloadDataForRegisteredObjects: toDeleteLocalRecords: para tener en cuenta este nuevo BOOL, toDelete .:

  ... [[SDAFParseAPIClient sharedClient] enqueueBatchOfHTTPRequestOperations: operaciones progressBlock: ^ (NSUInteger numberOfCompletedOperations, NSUInteger totalNumberOfOperations) {} completionBlock: ^ (operaciones NSArray *) {if (! DeLate) {[self processJSONDataRecordsIntoCoreData];  } Else {[self processJSONDataRecordsForDeletion];  }}];  ... 

Los únicos cambios están en completionBlock para enqueueBatchOfHTTPRequestOperations ..

Ahora que -processJSONDataRecordsIntoCoreData ya no es el último método que se debe ejecutar en el proceso de sincronización, debe quitar la siguiente línea de su implementación:

  [Self executeSyncCompletedOperations]; 

Las líneas finales de este método ahora deben verse como:

  ... [managedObjectContext performBlockAndWait: ^ {NSError * error = nil;  If (! [ManagedObjectContext save: & error]) {NSLog (@ "No se puede guardar el contexto para la clase% @", className);  }}];  [Self deleteJSONDataRecordsForClassWithName: className];  } [Self downloadDataForRegisteredObjects: NO toDeleteLocalRecords: SI];  } 

Ahora crea y ejecuta la aplicación! Una vez que la aplicación se está ejecutando, vaya a Parse Data Browser y elimine uno de sus registros. Después de borrar el registro, vuelve a la aplicación y presiona el botón Refresh para verlo desaparecer. Santa vaca - como la magia, se ha ido! Ahora puede agregar y quitar registros del servicio remoto y su aplicación siempre permanecerá sincronizada.

Empujar los registros creados localmente a servicio remoto

En esta sección, creará una característica que impulsará los registros creados dentro de la aplicación al servicio remoto. Comience agregando un nuevo método a SDAFParseAPIClient para manejar esta comunicación. Abra SDAFParseAPIClient.h y agregue la siguiente declaración de método:

  - (NSMutableURLRequest *) POSTRequestForClass: (NSString *) className parámetros: (NSDictionary *) parámetros; 

Ahora implemente este método:

  - (NSMutableURLRequest *) POSTRequestForClass: (NSString *) className parámetros: (NSDictionary *) parámetros {NSMutableURLRequest * request = nil;  Request = [self requestWithMethod: @ ruta "POST": [NSString stringWithFormat: @ "classes /% @", className] parámetros: parámetros];  solicitud de devolución;  } 

Este nuevo método simplemente toma un className y un NSDictionary de parámetros que es su JSON datos para publicar en el servicio web. Echa un vistazo a la creación de objetos con el Parse REST API para obtener información sobre lo que harás en este próximo paso. Esencialmente, es un estándar HTTP POST - por lo que si usted tiene alguna experiencia web con operaciones HTTP, esto debe ser muy familiar!

A continuación, necesitará una forma de determinar qué registros deben ser enviados al servicio remoto. Ya tiene un indicador syncStatus existente en SDSyncEngine.h que puede utilizarse para este propósito. Actualice su enum para que parezca:

  Typedef enum {SDObjectSynced = 0, SDObjectCreated,} SDObjectSyncStatus; 

A continuación, tendrá que utilizar este nuevo indicador cuando los objetos se crean localmente. Vaya a SDAddDateViewController.m e importe el encabezado SDSyncEngine para que el enum sea visible:

  #import "SDSyncEngine.h" 

A continuación, actualice el método -saveButtonTouched: para establecer el indicador syncStatus en SDObjectCreated cuando se agregue un nuevo registro:

  - (IBAction) saveButtonTouched: (id) remitente {if (! [Self.nameTextField.text isEqualToString: @ ""] && self.datePicker.date) {[self.date setValue: self.nameTextField.text forKey: @ "nombre "];  [Self.date setValue: [fecha_de_automatizaciónSetToMidnightUsingDate: self.datePicker.date] forKey: @ "fecha"];  // Establece el indicador syncStatus en SDObjectCreated [self.date setValue: [NSNumber numberWithInt: SDObjectCreated] forKey: @ "syncStatus"];  If ([self.entityName isEqualToString: @ "Holiday"]) {... 

Cuando se agregue un nuevo registro, será útil intentar empujar el registro al servicio remoto inmediatamente, para guardar al usuario un paso de sincronización más adelante. Actualice el addDateCompletionBlock en -prepareForSegue: remitente para llamar a startSync en el addDateCompletionBlock para empujar inmediatamente el registro al servicio remoto.

  [AddDateViewController setAddDateCompletionBlock: ^ {[self loadRecordsFromCoreData];  [Self.tableView reloadData];  [[SDSyncEngine sharedEngine] startSync];  }]; 

Para enviar sus registros de datos básicos al servicio remoto, debe traducirlos al formato JSON apropiado para el servicio remoto y utilizar su nuevo método en SDAFParseAPIClient. La cadena JSON para días festivos y cumpleaños será diferente, por lo que necesitará dos métodos diferentes. Para mantener el motor de sincronización desacoplado de sus entidades de datos principales, agregue un método de categoría en NSManagedObject que se puede llamar desde el motor de sincronización para obtener una representación JSON del registro en datos principales.

Vaya a Archivo \ Nuevo \ Archivo ..., elija Categoría iOS \ Cocoa Touch \ Objective-C y haga clic en Siguiente. Ingrese NSManagedObject para Category en, el nombre de la nueva categoría JSON, haga clic en Siguiente y Crear.

Ahora tendrá dos archivos nuevos, NSManagedObject + JSON.h y NSManagedObject + JSON.m. Agregue dos nuevas declaraciones de método en NSManagedObject + JSON.h:

  - (NSDictionary *) JSONToCreateObjectOnServer;  - (NSString *) dateStringForAPIUsingDate: (NSDate *) fecha; 

Este método devolverá un NSDictionary que representa el valor JSON requerido para crear el objeto en el servicio remoto. Utilizará NSDictionary ya que es fácil de crear en pura sintaxis de Objective-C y es lo que espera su método POST en SDAFParseAPIClient. AFNetworking se encargará de la tarea para convertir NSDictionary a una cadena para usted al enviar la solicitud POST al servidor.

Implementar el método de categoría en NSManagedObject + JSON.m:

  - (NSDictionary *) JSONToCreateObjectOnServer {@throw [NSException exceptionWithName: @ "JSONStringToCreateObjectOnServer Not Overridden" razón: @ "Debe reemplazar JSONStringToCreateObjectOnServer en la clase NSManagedObject" userInfo: nil];  Return nil;  } 

Esto parece una implementación bastante extraña, ¿no? El problema aquí es que no hay una implementación genérica posible para este método. TODAS las subclases de NSManagedObject deben implementar este método por sí mismas reemplazándolo. Cada vez que una subclase NSmanagedObject NO implementa este método, se lanzará una excepción - ¡para mantenerte en línea! :]

Nota: Una palabra de precaución - en este siguiente paso, que está a punto de editar algunos archivos derivados. Si edita su modelo de datos básicos y regenera estos archivos definidos, los cambios se perderán. Es muy molesto y desperdiciador de tiempo cuando te olvidas de hacer esto, así que ten cuidado! Una forma de evitar este problema es generar una categoría en la subclase NSManagedObject tal como lo hizo para NSManagedObject + JSON; Todos los métodos personalizados van en la categoría y no los perderá cuando regenere el archivo. Usted sabe lo que dicen - una línea de código en el tiempo guarda nueve ... o algo así! :]

Abra Holiday.m e importe la categoría y los encabezados del motor de sincronización:

  #import "NSManagedObject + JSON.h" #import "SDSyncEngine.h" 

Ahora siga adelante e implemente el método -JSONToCreateObjectOnServer:

  - (NSDictionary *) JSONToCreateObjectOnServer {NSDictionary * date = [NSDictionary dictionaryWithObjectsAndKeys: @ "Fecha", @ "tipo___", [[SDSyncEngine sharedEngine] dateStringForAPIUsingDate: self.date], @ "iso", nil];  NSDictionary * jsonDictionary = [NSDictionary dictionaryWithObjectsAndKeys: self.name, @ "nombre", self.details, @ "details", self.wikipediaLink, @ "wikipediaLink", fecha, @ "fecha", nil];  Return jsonDictionary;  } 

Esta implementación es bastante sencilla. Ha creado un NSDictionary que representa la estructura JSON requerida por la API de servicios remotos. Primero el código construye la estructura requerida para el campo Fecha, y luego construye el resto de la estructura y pasa en su fecha NSDictionary.

Ahora haz lo mismo para Birthday.m:

  #import "NSManagedObject + JSON.h" #import "SDSyncEngine.h" 

No se olvide de importar la categoría y encabezados del motor de sincronización:

  - (NSDictionary *) JSONToCreateObjectOnServer {NSDictionary * date = [NSDictionary dictionaryWithObjectsAndKeys: @ "Fecha", @ "tipo___", [[SDSyncEngine sharedEngine] dateStringForAPIUsingDate: self.date], @ "iso", nil];  NSDictionary * jsonDictionary = [NSDictionary dictionaryWithObjectsAndKeys: self.name, @ "name", self.giftIdeas, @ "giftIdeas", self.facebook, @ "facebook", fecha, @ "fecha", nil];  Return jsonDictionary;  } 

Los lectores de ojos de águila notarán que es exactamente el mismo código, con las propiedades apropiadas para objetos de cumpleaños en lugar de objetos de vacaciones.

Como se señaló en la parte 1, el formato de la fecha Parse es sólo un poco diferente de NSDate - pero lo suficiente para causar un poco de trabajo extra. Necesitará una función pequeña para realizar los cambios necesarios en las cadenas de fecha. Agregue un método y su declaración de interfaz a SDSyncEngine.h:

  - (NSString *) dateStringForAPIUsingDate: (NSDate *) fecha; 

Y a SDSyncEngine.m:

  - (NSString *) dateStringForAPIUsingDate: (NSDate *) date {[self initializeDateFormatter];  NSString * dateString = [self.dateFormatter stringFromDate: date];  // remove Z dateString = [dateString substringWithRange: NSMakeRange (0, [dateString longitud] -1)];  // agrega milisegundos y vuelve a poner Z en dateString = [dateString stringByAppendingFormat: @ ". 000Z"];  Return dateString;  } 

Ahora para usar la nueva categoría en SDSyncEngine.m:

  #import "NSManagedObject + JSON.h" 

Importe su categoría JSON de NSManagedObject y añada el siguiente método, debajo de -newManagedObjectWithClassName: forRecord:

  - (void) postLocalObjectsToServer {NSMutableArray * operaciones = [matriz NSMutableArray];  // // Iterate sobre todas las clases de registro a sync // for (NSString * className en self.registeredClassesToSync) {// // Recupera todos los objetos de Core Data cuyo syncStatus es igual a SDObjectCreated // NSArray * objectsToCreate = [self managedObjectsForClass: ClassName withSyncStatus: SDObjectCreated];  // // Iterate sobre todos los objetos obtenidos que syncStatus es igual a SDObjectCreated // para (NSManagedObject * objectToCreate en objectsToCreate) {// // Obtener la representación JSON del NSManagedObject // NSDictionary * jsonString = [objectToCreate JSONToCreateObjectOnServer];  // // Crear una petición utilizando su método POST con la representación JSON de NSManagedObject // NSMutableURLRequest * request = [[SDAFParseAPIClient sharedClient] POSTRequestForClass: className parámetros: jsonString];  {// // Establece el bloque de finalización para la operación para actualizar el NSManagedObject con el createdDate desde // el servicio remoto y objectId [AFP] , A continuación, establezca el syncStatus en SDObjectSynced para que el motor de sincronización no // intente volver a crearlo // NSLog (@ "Success creation:% @", responseObject);  NSDictionary * responseDictionary = responseObject;  NSDate * createdDate = [self dateUsingStringFromAPI: [responseDictionary valueForKey: @ "createdAt"]];  [ObjectToCreate setValue: createdDate forKey: @ "createdAt"];  [ObjectToCreate setValue: [responseDictionary valueForKey: @ "objectId"] forKey: @ "objectId"];  [ObjectToCreate setValue: [NSNumber numberWithInt: SDObjectSynced] forKey: @ "syncStatus"];  } Error: ^ (AFHTTPRequestOperation * operación, NSError * error) {// // Registra un error si hubo uno, se debe realizar el manejo de errores apropiado si es necesario, en este caso no puede // ser obligado a hacer algo como el El objeto intentará sincronizar de nuevo la próxima vez.  Podría haber una posibilidad // de que los datos estuvieran mal formados, de campos faltantes, de campos adicionales presentes, etc ... así que es una buena idea // determinar el mejor enfoque de manejo de errores para sus aplicaciones de producción.  // NSLog (@ "Creación fallida:% @", error);  }];  // // Añadir todas las operaciones a las operaciones NSArray // [operaciones addObject: operation];  }} // // Pasa la matriz de operaciones al sharedClient para que se ejecuten todos // [SDAFParseAPIClient sharedClient] enqueueBatchOfHTTPRequestOperations: operaciones progressBlock: ^ (NSUInteger numberOfCompletedOperations, NSUInteger totalNumberOfOperations) {NSLog (@ "Completado% d de% d Crear operaciones ", numberOfCompletedOperations, totalNumberOfOperations);  } CompletionBlock: ^ (operaciones NSArray *) {// // Establece el bloque de finalización para guardar el contextContext // if ([count de operaciones]> 0) {[[SDCoreDataController sharedInstance] saveBackgroundContext];  } // // Invoca executeSyncCompletionOperations ya que este es ahora el paso final del flujo del motor de sincronización // [self executeSyncCompletedOperations];  }];  } 

Ahora vaya al método -processJSONDataRecordsForDeletion y reemplace

  [Self executeSyncCompletedOperations]; 

con:

  [Self postLocalObjectsToServer]; 

¡Crea y ejecuta la aplicación! Adelante y crear un nuevo registro; Crear un día de fiesta y un registro de cumpleaños si te sientes valiente! :] Después de que termine la sincronización, vaya al explorador de datos en Parse y debería ver su registro recién creado. ¡Funciona! Este material de sincronización es fácil; Parece que es hora de disparar a todos los chicos de Java!

Eliminar registros en el servidor cuando se elimina localmente

Ahora intente borrar un registro (deslizar para borrar) y luego presione el botón de actualización.

Cómo sincronizar datos básicos con un servicio Web && num; 8211 & semi;  Parte 2


Whoa, ¿qué está pasando aquí? No, por desgracia los extranjeros no son responsables de este comportamiento! El problema es que no realiza el seguimiento cuando se elimina un objeto localmente y envía esa información al servicio remoto. Primero debes agregar otra opción de syncStatus abierta SDSyncEngine.h y actualizar tu enum para reflejar lo siguiente:

  Typedef enum {SDObjectSynced = 0, SDObjectCreated, SDObjectDeleted,} SDObjectSyncStatus; 

A continuación, debe agregar un nuevo método SDAFParseAPIClient que procesará la eliminación en el servicio remoto.

Agregue la siguiente declaración de método a SDAFParseAPIClient.h:

  - (NSMutableURLRequest *) DELETERequestForClass: (NSString *) className forObjectWithId: (NSString *) objectId; 

Ahora implemente el método en SDAFParseAPIClient.m:

  - (NSMutableURLRequest *) DELETERequestForClass: (NSString *) className paraObjectWithId: (NSString *) objectId {NSMutableURLRequest * request = nil;  Request = [self requestWithMethod: @ "DELETE" path: [NSString stringWithFormat: @ "classes /% @ /% @", className, objectId] parámetros: nil];  solicitud de devolución;  } 

A continuación, debe marcar los registros como eliminados cuando el usuario los elimine. Open SDDateTableViewController.m y update -tableView: commitEditingStyle: forRowAtIndexPath: con la siguiente implementación:

  - (void) tableView: (UITableView *) tableView commitEditingStyle: (UITableViewCellEditingStyle) editingStyle forRowAtIndexPath: (NSIndexPath *) indexPath {if (editingStyle == UITableViewCellEditingStyleDelete) {NSManagedObject * date = [self.dates objectAtIndex: indexPath.row];  [Self.managedObjectContext performBlockAndWait: ^ {// 1 if ([[date valueForKey: @ "objectId"] isEqualToString: @ ""] || [fecha valueForKey: @ "objectId"] == nil) {[self.managedObjectContext deleteObject :fecha];  } Else {[date setValue: [NSNumber numberWithInt: SDObjectDeleted] forKey: @ "estado de sincronización"];  } NSError * error = nil;  BOOL saved = [self.managedObjectContext save: & error];  If (! Saved) {NSLog (@ "Error al guardar el contexto principal:% @", error);  } [[SDCoreDataController sharedInstance] saveMasterContext];  [Self loadRecordsFromCoreData];  [Self.tableView reloadData];  }];  }} 

Eche un vistazo a la marca de comentario "1". Esta línea fue eliminada:

  [Self.managedObjectContext deleteObject: date]; 

Y esta línea fue añadida:

  If ([[date valueForKey: @ "objectId"] isEqualToString: @ ""] || [date valueForKey: @ "objectId"] == nil) {[self.managedObjectContext deleteObject: date];  } Else {[date setValue: [NSNumber numberWithInt: SDObjectDeleted] forKey: @ "estado de sincronización"];  } 

Ya no se está eliminando el registro de los datos básicos. En el nuevo modelo, si el registro no tiene un objectId (lo que significa que no existe en el servidor) se elimina el registro de inmediato como lo era antes. De lo contrario, se establece el syncStatus a SDObjectDeleted. Esto es para que el registro todavía está alrededor cuando es hora de enviar la petición al servidor para tenerla suprimida.

Esto plantea un nuevo problema sin embargo. (¿Puedes verlo tú mismo, antes de leer más?)

¡Los registros borrados siguen apareciendo en la lista! (Y no, este no es debido a los extranjeros tampoco). Esto indudablemente confundirá al usuario, y es probable que intente eliminarlo una y otra vez. Debe actualizar a continuación su SDDateTableViewController para no mostrar registros cuyo syncStatus se establece en SDObjectDeleted.

Agregue una línea en su método -loadRecordsFromCoreData:

  - (void) loadRecordsFromCoreData {[self.managedObjectContext performBlockAndWait: ^ {[self.managedObjectContext reset];  NSError * error = nil;  NSFetchRequest * request = [[NSFetchRequest alloc] initWithEntityName: self.entityName];  [Request setSortDescriptors: [NSArray arrayWithObject: [NSSortDescriptor sortDescriptorWithKey: @ "fecha" ascendente: SÍ]]];  // 1 [request setPredicate: [NSPredicate predicateWithFormat: @ "syncStatus! =% D", SDObjectDeleted]];  Self.dates = [self.managedObjectContext executeFetchRequest: error de solicitud: & error];  }];  } 

La línea después del comentario "1" establece un predicado en el NSFetchRequest para ignorar registros cuyo syncStatus es igual a SDObjectDeleted. (Eso no fue tan difícil de arreglar, esos alienígenas tendrán que intentar un poco más difícil la próxima vez).

Ahora crea y ejecuta la aplicación! Intente borrar un registro; Los registros eliminados ya no deben seguir reapareciendo en su lista cuando presiona el botón de actualización.

Sin embargo, todavía queda un problema. ¿Puedes decir lo que has olvidado hacer?

Echa un vistazo a Parse - los registros seguirán existiendo! (¡Ni siquiera trate de culpar a esos alienígenas de nuevo!) Ahora debe modificar el motor de sincronización para utilizar su nuevo método en SDAFParseAPIClient.

Beneath -postLocalObjectsToServer, agregue el siguiente método

  - (void) deleteObjectsOnServer {NSMutableArray * operaciones = [matriz NSMutableArray];  // // Iterate sobre todas las clases registradas para sincronizar // for (NSString * className en self.registeredClassesToSync) {// // Buscar todos los registros de Core Data cuyo syncStatus es igual a SDObjectDeleted // NSArray * objectsToDelete = [self managedObjectsForClass: ClassName withSyncStatus: SDObjectDeleted];  // // Iterate sobre todos los registros obtenidos de Core Data // para (NSManagedObject * objectToDelete en objectsToDelete) {// // Crear una solicitud para cada registro // NSMutableURLRequest * request = [[SDAFParseAPIClient sharedClient] DELETERequestForClass: className forObjectWithId: ObjectToDelete valueForKey: @ "objectId"]];  AFHTTPRequestOperation * operation = [[SDAFParseAPIClient sharedClient] HTTPRequestOperationWithRequest: solicitud de éxito: ^ (AFHTTPRequestOperation * operación, id responseObject) {NSLog (@ "Eliminación de éxito:% @", responseObject);  // // En el bloque de terminación de operaciones elimine NSManagedObject de los datos de Core localmente ya que ha sido // eliminado en el servidor // [[[SDCoreDataController sharedInstance] backgroundManagedObjectContext] deleteObject: objectToDelete];  } Fallo: ^ (operación AFHTTPRequestOperation *, error NSError *) {NSLog (@ "Error al eliminar:% @", error);  }];  // // Añadir cada operación a la matriz de operaciones // [operaciones addObject: operation];  }} [SDAFParseAPIClient sharedClient] enqueueBatchOfHTTPRequestOperations: operaciones progressBlock: ^ (NSUInteger numberOfCompletedOperations, NSUInteger totalNumberOfOperations) {} completionBlock: ^ (operaciones NSArray *) {if ([operaciones contadas]> 0) {// // Guardar el contexto de fondo después Todas las operaciones han completado // [[SDCoreDataController sharedInstance] saveBackgroundContext];  } // // Ejecuta las operaciones de sincronización completadas // [self executeSyncCompletedOperations];  }];  } 

Ahora que este método es la última parte del flujo del motor de sincronización, debe actualizar su método -postLocalObjectsToServer reemplazando:

  [Self executeSyncCompletedOperations]; 

con:

  [Self deleteObjectsOnServer]; 

¡Y eso es! ¡Felicitaciones - has terminado - a pesar de esa irritante interferencia alienígena! ;] Ahora todos los registros creados o eliminados en tu servicio remoto aparecerán o desaparecerán en tu aplicación. Lo contrario también es cierto: todos los registros creados o borrados localmente se reflejarán en el servicio remoto.

A dónde ir desde aquí?

Aquí está el proyecto de ejemplo final de esta serie de tutoriales.

Aunque tengas una aplicación bastante redondeada, todavía hay algunas maneras de mejorarla. La siguiente progresión natural sería añadir la capacidad de los usuarios para editar registros localmente; Así mismo, cualquier edición realizada en el servicio local debería sincronizarse con la aplicación.

También hay la omisión de agregar imágenes en la aplicación. Dependiendo del servicio remoto, usted podría hacer esto en una variedad de maneras. Éste es sobre todo un detalle de la puesta en práctica, pero es definitivamente algo que los usuarios desearían. Para darle un punto de partida, debe aplicarse la misma estrategia POST descrita anteriormente para empujar registros al servidor.

La sincronización es una tarea increíblemente difícil en el mundo móvil de iOS. Dependiendo de la cantidad de datos que deba sincronizarse, la estrategia descrita en este tutorial puede no ser óptima. A pesar de que la eficiencia fue abordada a lo largo de este tutorial, normalmente es mejor evitar la "optimización prematura": ajustar su estrategia a las necesidades de su aplicación siempre será mejor que cortar y pegar una solución enlatada.

Al extender su aplicación, si encuentra que las huellas de memoria están aumentando más allá de los niveles aceptables, debe buscar en el uso de piscinas de autorelease en los bucles de procesamiento. Un buen consejo es utilizar los instrumentos para ayudarle a encontrar los puntos donde el uso de la memoria es alto. También puede encontrar que no debe invocar el proceso de sincronización con demasiada frecuencia o demasiado pronto, o puede que tenga que evitar el uso de la aplicación durante la sincronización inicial si está esperando una gran cantidad de datos a venir.

Espero que este tutorial te ayude a determinar la mejor estrategia de sincronización en tus aplicaciones. También espero poder hacerlo tan genérico como sea posible para que puedas usarlo en tus aplicaciones del mundo real.

Si tiene alguna pregunta o comentario sobre este tutorial, por favor, únase a la discusión del foro a continuación.

Cómo sincronizar datos básicos con un servicio Web && num; 8211 & semi;  Parte 2

Este es un post de iOS Tutorial miembro del equipo Chris Wagner, un entusiasta en la ingeniería de software siempre tratando de mantenerse por delante de la curva. También puedes encontrarlo en Google+.

Etiqueta:

Artículos relacionados

Popular

Último