18

NSUbiquitousKeyValueStoreを使用していくつかのアプリ設定を保存しています。私の論理は次のとおりです。データをローカルに保存するときは、バックアップとしてもNSUbiquitousKeyValueStoreに保存します。設定が必要な場合は、ローカルで読み取り、ローカルでデータが見つからない場合(たとえば、アプリを再インストールした後)にのみiCloudKey-Valueストアを使用します。ユーザーが1つのicloudIDを共有する複数のデバイスを持っている場合、ユーザーは1つのデバイスに設定を書き込んで、別のデバイスにダウンロードできます(書き換えについて警告します)。

奇妙な問題があります。手順:

  1. アプリをインストールし、そのデータをNSUbiquitousKeyValueStoreに保存します。データがそこにあることを確認しました。
  2. アプリを削除しました(データがまだiCloudに残っていると仮定します)。
  3. 念のため数分待ってから、Xcode内からアプリをインストールして起動しました。
  4. [[NSUbiquitousKeyValueStore defaultStore] dataForKey:@ "mykeyname"]を使用して設定キーを読み取ろうとしました-問題ない場合もありますが、キーが見つからない場合もあります。
  5. 15秒間待ってから、再試行しました。成功。混乱している。

したがって、iOSは、私のアプリのリモートキー値ストレージをdataForKey:呼び出しでローカルに使用できるようにするために時間がかかるようです。もし私がそのようなシステムを書いたとしたら(実際に私は書いた-しばらく前に、別の人生で)、キー値データを要求して受け取る前に明らかに遅れがなければならない。そこで、「最初の起動時にキー値ストレージのダウンロード/同期を終了しました」などの通知を受け取りたいと思います。

私が理解している限り、メインスレッドでNSUbiquitousKeyValueStoreを同期的に操作できます(これは私にとって便利です)。しかし、[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]は有効なURLを返し、「キーが見つかりません」というメッセージが表示されます。だから私はそれに頼ることができません。NSUbiquitousKeyValueStoreが機能し、ダウンロードされていることを確認する方法はありますか?特に遅いインターネットでは重要です。

アップデート

[[NSUbiquitousKeyValueStore defaultStore] synchronize](Appleドキュメントに記載されている)をinitとloadに追加すると、少し役に立ちました。それでもiCloudには多くの質問があります。

昨日、電話1のKey-Valueストアにデータを正常に保存し、電話2で復元しました。今日、電話2のアプリを削除し、データを復元しようとしました。しかし、[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]でも有効なURLが返され、[[NSUbiquitousKeyValueStore defaultStore] synchronize]を呼び出しました。dataForKey:MY_DATA_KEYを呼び出すとnilになります。

電話1でicloudからデータを復元しようとすると(アプリはまだインストールされています)、成功しますが、この電話に再インストールすると、アプリの復元は成功しなくなります。

一時的な解決策は、「iCloudをオフにする-> Documents&Data-ネットワークをオフにしてからオンにする-Documents&Dataをオンにする」ですが、数分待ってから動作するはずです。

だから、質問:

  1. iCloudでそのような問題がありますか?
  2. データが利用できないか、まだダウンロードされていないかを確認する方法はありますか?
  3. iCloudの既知の「レイテンシ」はありますか?私は約7秒聞いたが、それは明らかに真実ではない。
  4. アプリがインストールされていない場合、iCloudデータの更新はかなり高速(秒)のようですが、アプリを再インストールすると、iCloudはKey-Valueストアを実現するのに数分かかります。このプロセスを強制する方法はありますか?

PS 以下は、参考のために私のCloudHelperです-iCloudKey-Valueストアとの間でバイナリデータを読み書きするための非常に単純なc++クラスです。コンパイル可能ではありません。より明確にするために、SOに合わせて調整しました。エンジン関連のコードを削除しました。それでも、MySystem :: ...呼び出しを削除すると、かなりうまく機能します。私が前に述べたことを除いて。

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;
}

更新2

2016年です。AndroidはiOSの邪悪な双子になり、人類は重力波を発見し、Higgsは彼のノーベルを受け取り、MicrosoftはNokiaを買収して殺害しました。しかし、iCloudはまだそれがそうであったのと同じくらい愚かです。

最後に、いくつかのVPSで独自のネットワークサービスのスタックを作成しました。サードパーティのサービスのほとんどは不安定で予測できないため、使用を拒否しました。それでも私はiCloudが必要です。アップルのもう一人の死んだ子供は働かないからです。SecKeyChain。私のゲームが始まると、そのサービスは停止します。そこで、再インストール後もユーザーを区別するためにランダムなUUIDをクラウドに保存することにしました(デバイスIDはもうありません)。しかし、何がうまくいかない可能性がありますか?すべての!このばかげたs*itをエラーなしでデプロイするために2日間を費やしましたが、今ではデータが失われることがあります。

ありがとうアップル、ありがとう、ありがとう、ありがとう!ラララ!ヒップヒップフーレイ!(サーカス音楽の音、しだれに消えていく)

4

3 に答える 3

4

結論

一時的な解決策は次のとおりです。-キー値ストアからデータを取得する前に同期を呼び出します-「iCloudをオフにする->Documents&Data-ネットワークをオフにしてからもう一度オンにする-Documents&Dataをオンにする」ことを確認しますが、数分待つ必要がありますiCloudは必要なすべてのデータをダウンロードします

注:アプリがインストールされ、キーバリューストアですでに機能している(保存/ロードされている)場合、iCloudデータの更新はかなり高速です(7〜15秒)が、アプリを再インストールすると、icloudがキーを実現するのに数分かかるようです-バリューストア。

icloudはほとんど使えない機能のように見えるので、あなたの考えを聞いてうれしいです。しかし、同じ機能を取得するためだけに独自のサーバーをセットアップしたくはありません。

于 2012-09-22T00:05:44.760 に答える
1

1つのダミーキーをNSUbiquitousKeyValueStoreに設定し、アプリの起動時に同期を呼び出しています。結果は100%の解決策ではありませんが、いくらか良くなります。あなたはこれを試すことができます。

于 2013-02-28T06:09:10.247 に答える
-1

明らかに、遅いネットワークを待っている間、アプリがハングすることはありません。それはすべてiCloudデザインガイドにあります。

登録しNSUbiquitousKeyValueStoreDidChangeExternallyNotification、-synchronizeを呼び出してください。そうすれば、最終的に通知が届くはずです。

データがすでに最新である場合、通知を受け取ることはないと思います。また、データの古さを知るための面倒な方法はないと思います。

于 2012-09-22T22:36:55.227 に答える