iCloud NSUbiquitousKeyValueStore retraso de acceso / sincronización inicial: ¿cómo gestionarlo?

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 copia de seguridad. Cuando necesito ajustes, leo localmente y solo uso el almacén de valores clave de iCloud si no se encuentran datos localmente (después de reinstalar la aplicación, por ejemplo). Si el usuario tiene varios dispositivos que comparten una identificación de icloud, puede escribir la configuración en un dispositivo y descargarla en otro (le advierto sobre la reescritura).

Tengo un problema extraño. Pasos:

Instala una aplicación y guarda sus datos en NSUbiquitousKeyValueStore. Asegúrese de que los datos están allí.Se eliminó la aplicación (asumiendo que los datos aún persisten en iCloud).Esperé varios minutos por si acaso, luego instalé e inicié la aplicación desde Xcode.Intenté leer una clave de configuración usando [[NSUbiquitousKeyValueStore defaultStore] dataForKey: @ "mykeyname"] - ¡a veces está bien, pero a veces no se encuentra la clave!Esperó 15 segundos, lo intentó de nuevo. Éxito. Confuso.

Así que parece que ios necesita algo de tiempo para hacer que el almacenamiento remoto de valor clave para mi aplicación esté disponible localmente para dataForKey: call. Si escribí un sistema así (en realidad lo hice, hace algún tiempo, en otra vida) obviamente debe haber un retraso antes de preguntar y recibir datos de valor-clave. Así que me gustaría recibir una notificación que diga: "terminamos de descargar / sincronizar el almacenamiento de valor clave en el primer inicio" o algo similar.

Según tengo entendido, puedo trabajar con NSUbiquitousKeyValueStore en el hilo principal de forma síncrona (lo que es conveniente para mí). Pero [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier: nil] devuelve una URL válida, y luego aparece "no se encuentra la clave". Así que no puedo confiar en ello. ¿Hay alguna forma de estar seguros de que NSUbiquitousKeyValueStore funciona y se descarga? Es importante especialmente con internet lento.

ACTUALIZAR

Agregar [[NSUbiquitousKeyValueStore defaultStore] sincronizar] (como está escrito en documentos de Apple) a init y cargar ayudó un poco. Todavía hay muchas preguntas para iCloud.

Ayer, he guardado con éxito los datos en el almacén de valores clave en el teléfono 1 y restaurado en el teléfono 2. Hoy he eliminado la aplicación en el teléfono 2 y he intentado restaurar los datos. Pero incluso [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier: nil] devolvió una URL válida y llamé a [[NSUbiquitousKeyValueStore defaultStore] sincronizar] No obtengo nada cuando llamo dataForKey: MY_DATA_KEY.

Cuando intenté restaurar los datos de icloud en el teléfono 1 (la aplicación aún está instalada), tiene éxito, pero cuando la 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 - activar y desactivar la red - activar Documentos y datos", pero también debe esperar varios minutos y luego debería funcionar.

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

PD A continuación se encuentra mi CloudHelper para su referencia: una clase de c ++ bastante simple para escribir / leer datos binarios en / desde el almacén de valores clave de iCloud. No es compilable, lo he adaptado para que SOA un poco más claro, eliminé mi código relacionado con el motor. Aún así, si eliminas MySystem :: ... las llamadas funcionan bastante bien. Excepto que lo 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 gemelo malvado de ios, la humanidad ha descubierto ondas gravitacionales, Higgs ha recibido su nobel, Microsoft ha comprado y matado a Nokia, todos vieron a Amber Heard y Jennifer Lawrence desnudas, por separado. Pero iCloud sigue siendo tan estúpido como era.

Finalmente he hecho mi propia pila de servicios de red en varios VPS. Me negué a usar servicios de terceros, porque la mayoría de ellos son inestables e impredecibles. Y sin embargo necesito iCloud. Porque otro niño nacido de la manzana no funciona. SecKeyChain. Su servicio muere cuando empieza mi juego. Así que decidí almacenar UUID aleatorio en la nube para distinguir a los usuarios (ya no hay una identificación de dispositivo) incluso después de reinstalar. Pero, ¿qué podría salir mal? ¡Todo! He pasado dos días para hacer que este estúpido * se implemente 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)

Respuestas a la pregunta(3)

Su respuesta a la pregunta