He estado trabajando en un método para sincronizar los datos centrales almacenados en una aplicación de iPhone entre múltiples dispositivos, como un iPad o una Mac. No hay muchos marcos de sincronización (si es que los hay) para usar con Core Data en iOS. Sin embargo, he estado pensando en el siguiente concepto:
- Se realiza un cambio en el almacén de datos central local y se guarda el cambio. (a) Si el dispositivo está en línea, intenta enviar el conjunto de cambios al servidor, incluida la ID del dispositivo que envió el conjunto de cambios. (b) Si el conjunto de cambios no llega al servidor, o si el dispositivo no está en línea, la aplicación agregará el conjunto de cambios a una cola para enviarlo cuando esté en línea.
- El servidor, sentado en la nube, combina los conjuntos de cambios específicos que recibe con su base de datos maestra.
- Después de fusionar un conjunto de cambios (o una cola de conjuntos de cambios) en el servidor de la nube, el servidor empuja todos esos conjuntos de cambios a los otros dispositivos registrados en el servidor utilizando algún tipo de sistema de sondeo. (Pensé en usar los servicios Push de Apple, pero aparentemente según los comentarios, este no es un sistema viable).
¿Hay algo elegante en lo que deba pensar? He examinado los marcos REST como ObjectiveResource , Core Resource y RestfulCoreData . Por supuesto, todos estos están trabajando con Ruby on Rails, a lo que no estoy vinculado, pero es un lugar para comenzar. Los principales requisitos que tengo para mi solución son:
- Cualquier cambio debe enviarse en segundo plano sin pausar el hilo principal.
- Debe usar el menor ancho de banda posible.
He pensado en varios de los desafíos:
- Asegurarse de que las ID de objeto para los diferentes almacenes de datos en diferentes dispositivos estén conectadas en el servidor. Es decir, tendré una tabla de ID de objeto e ID de dispositivo, que están vinculadas mediante una referencia al objeto almacenado en la base de datos. Tendré un registro (DatabaseId [exclusivo de esta tabla], ObjectId [exclusivo del elemento en toda la base de datos], Datafield1, Datafield2), el campo ObjectId hará referencia a otra tabla, AllObjects: (ObjectId, DeviceId, DeviceObjectId). Luego, cuando el dispositivo empuja hacia arriba un conjunto de cambios, pasará la Id. Del dispositivo y la Id. Del objeto desde el objeto de datos central en el almacén de datos local. Luego, mi servidor en la nube verificará el Id. Del objeto y el Id. Del dispositivo en la tabla AllObjects, y encontrará el registro para cambiar en la tabla inicial.
- Todos los cambios deben tener una marca de tiempo, para que puedan fusionarse.
- El dispositivo tendrá que sondear el servidor, sin usar demasiada batería.
- Los dispositivos locales también deberán actualizar todo lo que esté guardado en la memoria si / cuando se reciben cambios del servidor.
¿Hay algo más que me falta aquí? ¿Qué tipo de marcos debo mirar para hacer esto posible?
Respuestas:
Sugiero leer detenidamente e implementar la estrategia de sincronización discutida por Dan Grover en la conferencia de iPhone 2009, disponible aquí como documento pdf.
Esta es una solución viable y no es tan difícil de implementar (Dan implementó esto en varias de sus aplicaciones), superponiendo la solución descrita por Chris. Para una discusión teórica en profundidad sobre la sincronización, vea el artículo de Russ Cox (MIT) y William Josephson (Princeton):
Sincronización de archivos con pares de tiempo de vectores
que se aplica igualmente bien a los datos centrales con algunas modificaciones obvias. Esto proporciona una estrategia general de sincronización mucho más robusta y confiable, pero requiere más esfuerzo para implementarse correctamente.
EDITAR:
Parece que el archivo pdf de Grover ya no está disponible (enlace roto, marzo de 2015). ACTUALIZACIÓN: el enlace está disponible a través de Way Back Machine aquí
El marco Objective-C llamado ZSync y desarrollado por Marcus Zarra ha quedado en desuso, dado que iCloud finalmente parece admitir la sincronización correcta de los datos centrales.
fuente
He hecho algo similar a lo que intentas hacer. Déjame decirte lo que he aprendido y cómo lo hice.
Supongo que tiene una relación uno a uno entre su objeto Core Data y el modelo (o esquema db) en el servidor. Simplemente desea mantener sincronizados los contenidos del servidor con los clientes, pero los clientes también pueden modificar y agregar datos. Si acerté, sigue leyendo.
Agregué cuatro campos para ayudar con la sincronización:
En el cliente, agregue código para establecer sync_status en 1 en su objeto modelo cada vez que algo cambie y necesite sincronizarse con el servidor. Los nuevos objetos modelo deben generar un GUID.
La sincronización es una sola solicitud. La solicitud contiene:
El servidor recibe la solicitud y hace esto:
La aplicación recibe la respuesta y hace esto:
Espero que eso ayude. Utilicé el registro de palabras y el modelo indistintamente, pero creo que entiendes la idea. Buena suerte.
fuente
MAX(last_modified)
, pero eso sería redundante ya que esMAX(last_modified)
suficiente. Elsync_status
tiene otro papel. Como escribí anteriormente,MAX(last_modified)
determina qué debe sincronizarse desde el servidor, mientrassync_status
determina qué necesita sincronizarse con el servidor.Si todavía está buscando un camino a seguir, busque en el móvil Couchbase. Esto básicamente hace todo lo que quieres. ( http://www.couchbase.com/nosql-databases/couchbase-mobile )
fuente
Similar a @Cris, he implementado una clase para la sincronización entre el cliente y el servidor y he resuelto todos los problemas conocidos hasta ahora (enviar / recibir datos a / desde el servidor, fusionar conflictos basados en marcas de tiempo, eliminar entradas duplicadas en condiciones de red poco confiables, sincronizar datos anidados y archivos, etc.)
Simplemente le dice a la clase qué entidad y qué columnas debe sincronizar y dónde está su servidor.
Puede encontrar la fuente, el ejemplo de trabajo y más instrucciones aquí: github.com/knagode/M3Synchronization .
fuente
Notifique al usuario que actualice los datos mediante notificación push. Use un hilo de fondo en la aplicación para verificar los datos locales y los datos en el servidor de la nube, mientras que el cambio ocurre en el servidor, cambie los datos locales, y viceversa.
Entonces, creo que la parte más difícil es estimar los datos en qué lado se invalida.
Espero que esto pueda ayudarte
fuente
Acabo de publicar la primera versión de mi nueva API de sincronización de Core Data Cloud, conocida como SynCloud. SynCloud tiene muchas diferencias con iCloud porque permite una interfaz de sincronización multiusuario. También es diferente de otras API de sincronización porque permite datos relacionales de varias tablas.
Obtenga más información en http://www.syncloudapi.com
Construido con iOS 6 SDK, está muy actualizado a partir del 27/09/2012.
fuente
Creo que una buena solución al problema de GUID es el "sistema de identificación distribuido". No estoy seguro de cuál es el término correcto, pero creo que así lo llamaban los documentos del servidor MS SQL (SQL usa / usa este método para bases de datos distribuidas / sincronizadas). Es bastante simple:
El servidor asigna todas las ID. Cada vez que se realiza una sincronización, lo primero que se verifica es "¿Cuántas ID me quedan en este cliente?" Si el cliente se está agotando, le pide al servidor un nuevo bloque de ID. El cliente luego usa ID en ese rango para nuevos registros. Esto funciona muy bien para la mayoría de las necesidades, si puede asignar un bloque lo suficientemente grande como para que "nunca" se agote antes de la próxima sincronización, pero no tan grande que el servidor se agote con el tiempo. Si el cliente alguna vez se agota, el manejo puede ser bastante simple, solo dígale al usuario "lo siento, no puede agregar más elementos hasta que sincronice" ... si está agregando esa cantidad de elementos, ¿no deberían sincronizarse para evitar datos obsoletos? problemas de todos modos?
Creo que esto es superior al uso de GUID aleatorios porque los GUID aleatorios no son 100% seguros y, por lo general, deben ser mucho más largos que una ID estándar (128 bits frente a 32 bits). Por lo general, tiene índices por ID y, a menudo, mantiene los números de ID en la memoria, por lo que es importante mantenerlos pequeños.
Realmente no quería publicar como respuesta, pero no sé si alguien lo vería como un comentario, y creo que es importante para este tema y no está incluido en otras respuestas.
fuente
Primero debe repensar cuántos datos, tablas y relaciones tendrá. En mi solución, implementé la sincronización a través de archivos de Dropbox. Observo cambios en el MOC principal y guardo estos datos en archivos (cada fila se guarda como json comprimido). Si hay una conexión a Internet que funciona, verifico si hay cambios en Dropbox (Dropbox me da cambios delta), los descargo y los combino (últimas victorias), y finalmente pongo los archivos modificados. Antes de la sincronización, pongo el archivo de bloqueo en Dropbox para evitar que otros clientes sincronicen datos incompletos. Al descargar los cambios, es seguro que solo se descarguen datos parciales (por ejemplo, pérdida de conexión a Internet). Cuando finaliza la descarga (total o parcial), comienza a cargar archivos en Core Data. Cuando hay relaciones no resueltas (no se descargan todos los archivos), deja de cargar archivos e intenta finalizar la descarga más tarde. Las relaciones se almacenan solo como GUID, por lo que puedo verificar fácilmente qué archivos cargar para tener una integridad de datos completa. La sincronización comienza después de realizar cambios en los datos principales. Si no hay cambios, comprueba los cambios en Dropbox cada pocos minutos y en el inicio de la aplicación. Además, cuando se envían cambios al servidor, envío una transmisión a otros dispositivos para informarles sobre los cambios, para que puedan sincronizarse más rápido. Cada entidad sincronizada tiene una propiedad GUID (guid se usa también como un nombre de archivo para los archivos de intercambio). También tengo una base de datos de sincronización donde almaceno la revisión de Dropbox de cada archivo (puedo compararlo cuando Dropbox delta restablece su estado). Los archivos también contienen el nombre de la entidad, el estado (eliminado / no eliminado), guid (igual que el nombre del archivo), revisión de la base de datos (para detectar migraciones de datos o para evitar la sincronización con versiones que nunca son de la aplicación) y, por supuesto, los datos (si la fila no se elimina). así puedo verificar fácilmente qué archivos cargar para tener integridad de datos completa. La sincronización comienza después de realizar cambios en los datos principales. Si no hay cambios, comprueba los cambios en Dropbox cada pocos minutos y en el inicio de la aplicación. Además, cuando se envían cambios al servidor, envío una transmisión a otros dispositivos para informarles sobre los cambios, para que puedan sincronizarse más rápido. Cada entidad sincronizada tiene una propiedad GUID (guid se usa también como un nombre de archivo para los archivos de intercambio). También tengo una base de datos de sincronización donde almaceno la revisión de Dropbox de cada archivo (puedo compararlo cuando Dropbox delta restablece su estado). Los archivos también contienen el nombre de la entidad, el estado (eliminado / no eliminado), guid (igual que el nombre del archivo), revisión de la base de datos (para detectar migraciones de datos o para evitar la sincronización con versiones que nunca son de la aplicación) y, por supuesto, los datos (si la fila no se elimina). así puedo verificar fácilmente qué archivos cargar para tener integridad de datos completa. La sincronización comienza después de realizar cambios en los datos principales. Si no hay cambios, comprueba los cambios en Dropbox cada pocos minutos y en el inicio de la aplicación. Además, cuando se envían cambios al servidor, envío una transmisión a otros dispositivos para informarles sobre los cambios, para que puedan sincronizarse más rápido. Cada entidad sincronizada tiene una propiedad GUID (guid se usa también como un nombre de archivo para los archivos de intercambio). También tengo una base de datos de sincronización donde almaceno la revisión de Dropbox de cada archivo (puedo compararlo cuando Dropbox delta restablece su estado). Los archivos también contienen el nombre de la entidad, el estado (eliminado / no eliminado), guid (igual que el nombre del archivo), revisión de la base de datos (para detectar migraciones de datos o para evitar la sincronización con versiones que nunca son de la aplicación) y, por supuesto, los datos (si la fila no se elimina).
Esta solución funciona para miles de archivos y alrededor de 30 entidades. En lugar de Dropbox, podría usar el almacén de claves / valores como servicio web REST, lo que quiero hacer más tarde, pero no tengo tiempo para esto :) Por ahora, en mi opinión, mi solución es más confiable que iCloud y, lo cual es muy importante, Tengo control total sobre cómo funciona (principalmente porque es mi propio código).
Otra solución es guardar los cambios de MOC como transacciones: se intercambiarán muchos menos archivos con el servidor, pero es más difícil hacer la carga inicial en el orden correcto en los datos centrales vacíos. iCloud funciona de esta manera, y también otras soluciones de sincronización tienen un enfoque similar, por ejemplo, TICoreDataSync .
- ACTUALIZACIÓN
Después de un tiempo, migré a Ensembles : recomiendo esta solución en lugar de reinventar la rueda.
fuente