iCloud NSUbiquitousKeyValueStore synchronization inicial / retraso de acceso: cómo manejar?

Estoy usando NSUbiquitousKeyValueStore para almacenar algunas configuraciones de la aplicación. Mi lógica es: cuando guardo datos localmente, los guardo en NSUbiquitousKeyValueStore también como una copy de security. Cuando necesito ajustes, leo localmente y solo uso el almacén de valores key de iCloud si no se encuentran datos de forma local (después de reinstalar la aplicación, por ejemplo). Si el usuario tiene varios dispositivos que comparten una ID icloud, puede escribir configuraciones en un dispositivo y downloadlas a otra (le advierto sobre la reescritura).

Tengo un problema extraño. Pasos:

  1. Instala una aplicación y guarda sus datos en NSUbiquitousKeyValueStore. Aseguré que los datos estén allí.
  2. Se eliminó la aplicación (suponiendo que los datos aún persistan en iCloud).
  3. Esperó varios minutos por si acaso, luego instaló y lanzó la aplicación desde dentro de Xcode.
  4. Intenté leer una key de configuration usando [[NSUbiquitousKeyValueStore defaultStore] dataForKey: @ "mykeyname"] – a veces está bien, ¡pero a veces no se encuentra la key!
  5. Esperé por 15 segundos, intenté de nuevo. Éxito. Confuso.

Por lo tanto, parece que ios necesita algo de time para que el almacenamiento remoto de valores key para mi aplicación esté disponible localmente para dataForKey: call. Si hubiera escrito un sistema de este tipo (en realidad lo hice, hace algún time, en otra vida), obviamente, debe haber un retraso antes de preguntar y recibir datos de valor key. Entonces me gustaría tener alguna notificación que diga: "terminamos de download / sincronizar almacenamiento de valor-key en el primer inicio" o algo similar.

Por lo que entiendo, puedo trabajar con NSUbiquitousKeyValueStore en el hilo principal sincrónicamente (lo cual es conveniente para mí). Pero [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier: nil] devuelve una url válida, y luego aparece "no se encuentra la key". Entonces no puedo confiar en eso. ¿Hay alguna manera de asegurarse de que NSUbiquitousKeyValueStore funciona y se descarga? Es importante especialmente con Internet lenta.

ACTUALIZAR

Agregando [[NSUbiquitousKeyValueStore defaultStore] synchronize] (como está escrito en apple docs) a init y load se ayudó un poco. Aún hay muchas preguntas para iCloud.

Ayer he guardado correctamente los datos en el almacén de valores de key en el teléfono 1 y restaurado en el teléfono 2. Hoy he eliminado la aplicación en el teléfono 2 e intenté restaurar los datos. Pero incluso [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier: nil] devolvió la URL válida y llamé a [[NSUbiquitousKeyValueStore defaultStore] sincronizar] Obtuve nil cuando invoco dataForKey: MY_DATA_KEY.

Cuando intenté restaurar los datos de icloud en el teléfono 1 (la aplicación todavía está instalada), tiene éxito, pero cuando reinstalé en este teléfono, la restauración de la aplicación ya no tiene éxito.

La solución temporal es: "desactivar iCloud-> Documentos y Datos – apagar y encender la networking – activar Documentos y Datos", pero también debe esperar varios minutos y luego debería funcionar.

Entonces, preguntas: 1. ¿Tienes problemas con iCloud? 2. ¿Hay alguna forma de averiguar si los datos no están disponibles o simplemente no se han descargado todavía? 3. ¿Hay alguna "latencia" conocida de iCloud? He escuchado sobre 7 segundos, pero obviamente no es cierto. 4. Parece que cuando la aplicación no está registrada, las actualizaciones de los datos de iCloud son bastante rápidas (segundos), pero cuando vuelves a instalar la aplicación, icloud necesita varios minutos para actualizar el almacén de valores key. ¿Hay alguna forma de forzar este process?


PS A continuación se muestra mi CloudHelper para su reference: una class c ++ bastante simple para escribir / leer datos binarys en / desde iCloud key-value store. No es comstackble, lo he adaptado para que sea más claro, eliminé el código relacionado con mi motor. Sin embargo, si elimina MySystem :: … llamadas, funciona bastante bien. Excepto que mencioné antes.

class CloudHelper { public: static bool init(); static void deInit(); //save our data to iCloud with static int saveData(unsigned char* data, int from, int count); //get our data from iCloud static unsigned char * loadData(int *retsize, int * retint); //does iCloud work for us static bool isEnabled(); //do we have our key in iCloud static int isAvailable(); static const int RESULT_OK = 0; static const int RESULT_NO_CONNECTION = 1; static const int RESULT_NOT_FOUND = 2; static const int RESULT_SYNC_ERROR = 3; private: static bool enabled; static NSURL *ubiq; }; bool CloudHelper::enabled = false; NSURL *CloudHelper::ubiq = NULL; #define MY_DATA_KEY @"my_data_key" int CloudHelper::saveData(unsigned char* data, int from, int count) { if ([NSUbiquitousKeyValueStore defaultStore]) { NSData *d = [[[NSData alloc] initWithBytes:(data + from) length:count] autorelease]; [[NSUbiquitousKeyValueStore defaultStore] setData:d forKey: MY_DATA_KEY)]; if ([[NSUbiquitousKeyValueStore defaultStore] synchronize] != TRUE) return RESULT_SYNC_ERROR; return RESULT_OK; } return RESULT_NO_CONNECTION; } unsigned char * CloudHelper::loadData(int *retsize, int * retint) { if ([NSUbiquitousKeyValueStore defaultStore]) { [[NSUbiquitousKeyValueStore defaultStore] synchronize]; NSData *d = [[NSUbiquitousKeyValueStore defaultStore] dataForKey: MY_DATA_KEY]; if (d != NULL) { if (retsize != NULL) *retsize = d.length; if (retint != NULL) *retint = RESULT_OK; return d.bytes; } else { if (retsize != NULL) *retsize = -1; if (retint != NULL) *retint = RESULT_NOT_FOUND; } } else { if (retsize != NULL) *retsize = -1; if (retint != NULL) *retint = RESULT_NO_CONNECTION; } return NULL; } int CloudHelper::isAvailable() { int result = RESULT_NO_CONNECTION; if ([NSUbiquitousKeyValueStore defaultStore]) { [[NSUbiquitousKeyValueStore defaultStore] synchronize]; NSData *d = [[NSUbiquitousKeyValueStore defaultStore] dataForKey: MY_DATA_KEY]; if (d != NULL) result = RESULT_OK; else result = RESULT_NOT_FOUND; } else result = RESULT_NO_CONNECTION; return result; } void CloudHelper::deInit() { enabled = false; [ubiq release]; } bool CloudHelper::init() { enabled = false; NSURL *ubiq_ = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]; [[NSUbiquitousKeyValueStore defaultStore] synchronize]; if (ubiq) { enabled = true; ubiq = [ubiq_ retain]; //save for further use } else { //is implemented elsewhere: this writes a local file with a counter, and if it is < REMINDER_COUNT allows us to show a warning to users bool allow = MySystem::isAllowToShowDialog(); if (allow) { //determines network state with Apple's Reachability if (!MySystem::isNetworkAvailable()) MySystem::showMessageBox(@"Network error"); //No network else MySystem::showMessageBox(@"You should log into your iCloud account to be able to backup your settings."); //No login } } return enabled; } 

ACTUALIZACIÓN 2

Es 2016. Android se ha convertido en el malvado gemelo de ios, la humanidad ha descubierto ondas gravitacionales, Higgs ha recibido su nobel, Microsoft ha comprado y asesinado a Nokia, todo el mundo vio a Amber Heard y Jennifer Lawrence desnudos, por separado. Pero iCloud sigue siendo tan estúpido como lo fue.

Finalmente, he creado mi propia stack de services de networking en varios VPS. Me negué a usar services de terceros, porque la mayoría de ellos son inestables e impnetworkingecibles. Y, sin embargo, necesito iCloud. Porque otro niño fallecido de manzana no funciona. SecKeyChain. Su service muere cuando comienza mi juego. Así que decidí almacenar un UUID aleatorio en la nube para distinguir a los usuarios (ya no existe la identificación del dispositivo) incluso después de reinstalar. ¿Pero qué podría salir mal? ¡Todo! ¡He pasado dos días para hacer este estúpido s * it para desplegar sin errores, y ahora pierde mis datos de vez en cuando!

Gracias Apple, gracias, gracias, gracias! La-la-la! ¡Hip hip hurra! (sonidos de música de circo, desvaneciéndose en llanto)

Conclusión

La solución temporal es: – llamar a sincronizar antes de get datos del almacén de valores de key – para asegurarse de que funcionaría "desactivar iCloud-> Documentos y datos – apagar y volver a estar en la networking – activar Documentos y datos", pero también debe esperar varios minutos antes iCloud descarga todos los datos necesarios

Nota: cuando la aplicación está instalada y ya funcionó (guardada / cargada) con las actualizaciones de almacenamiento de valor key de los datos de iCloud son bastante rápidas (7-15 segundos), pero cuando reinstala la aplicación, parece que icloud necesita varios minutos para actualizar la key, valor de tienda

Me encantaría escuchar tus pensamientos, porque icloud parece una característica casi inutilizable. Pero no quiero configurar mi propio server para get simplemente la misma funcionalidad.

Estoy configurando una key simulada para NSUbiquitousKeyValueStore y llamando a sincronizar al iniciar la aplicación. El resultado no es una solución al 100% sino algo mejor. Puedes probar esto.

Porque, obviamente, su aplicación no debe colgarse mientras espera un Netork lento. Todo está en la Guía de layout de iCloud .

Regístrese para NSUbiquitousKeyValueStoreDidChangeExternallyNotification , llame -sincronice, y es de esperar que una notificación llegue eventualmente.

Si los datos ya están actualizados, no creo que recibas una notificación, y no creo que haya una manera segura de saber cuántos años tiene la información.

    Intereting Posts