質問: UserDefaultsでのデータの取り扱いについて問題があり、皆さまのお知恵を拝借したいと思います。 わかる限りの情報を書き連ねるため長文となりますが、ぜひよろしくお願いいたします。 X-Codeでアプリを開発していますが、リリース環境にてUserDefaultsに保存しているデータが「【読みだせなかった】ような挙動」を見せています。 ユーザー様からのご指摘で発覚し数回のアップデートを行いましたが、どうやら見当違いの対策ばかりをやっていたようです。 しかもテスト環境(X-code、実機テスト)では再現できず、根本原因に至っていません。 結果、現状の把握や解決策の糸口が、全く見当もつかない状態です。 ### 想定している動き まず、仕様(というか期待する動き)は下記のとおりです。 * サーバ(DB)との通信でKeyとなる文字列を生成(毎起動時) * このKeyを用いて、DBにユーザーデータをバックアップしたり、読み出したりする。 * [defaults registerDefaults:dict]で保存。既にデータがある場合は更新されない(はず)。 * アプリを完全に削除でもしない限り、この値は永続的に使用できる(はず)。 ### 問題の動き 問題の現象は以下の通りです。 * Keyにしている文字列が、意図せず変更されている (同一ユーザーからのFeedbackで確認。不具合が起こるたびに、Keyが変わっている)。 * DBでKeyが参照できなかったため、新規ユーザーとして認識し新規レコード作成。 データは初期化してしまう。 * この現象はアップデート時に頻発(特に一部ユーザーにて)、アップデート時以外にも、発生していると思われる(Feedbackの内容より)。 --- 我ながら粗い仕様だと承知しております。 しかし、UserDefaultsのKeyが読み込めていない(であろう)状態では、アップデートの度にデータが消失してしまう危険性が残ってしまいます。 私自身、X-codeを触り始めたばかりなので、根本的な勘違い・見当違いをしているのかもしれません。 似たような現象の起こった方、問題が推測できる方、何かしらの糸口となるヒントでも構いません、アドバイスを頂けないでしょうか? よろしくお願いいたします。 ※補足※ 別質問にて、端末側でkeyを生成する危険性についてはご指摘を頂き、サーバにて生成を行うよう、現在対応中です。 【2016/02/04追記】 依頼により追記いたします。 > > >[defaults registerDefaults:dict]で保存。 > > Keyとして生成された文字列を、Dictionary型 dictに代入後、上記の記述によりdefaults(NSUserDefaults)に保存(というより初期値設定)しています。 > > > >既にデータがある場合は更新されない(はず) その根拠は? > > 上記の記述が「初期値設定」であり、前回の起動で初期値が設定されていた場合は、何も起こらないものだと認識しておりました。 > > (少なくとも、私が引き継いだ段階では上記の認識で組まれており、私もその認識で理解した次第です) > > > 毎起動時に新規にKeyを生成しているんですか? > > KeyにはUUID(identifierForVendor)を流用しています。これも引継ぎ時には既にあった記述ですが、前後の記述を見る限り『毎回記述をする必要性』は無いと感じています。 > > > >アプリを完全に削除でもしない限り、この値は永続的に使用できる(はず) その根拠は? こちらも「そういうものだ」という認識でした(引継ぎ時の組み方から判断して)。
回答: 今回の質問の説明はStripeさんがコメントされているように謎だらけなのですが、前回の質問の説明と合わせて読んで、なんとか理解できたので気になった点をコメントします。 まず今回の質問の説明で「[defaults registerDefaults:dict]で保存」と書かれていますが、`registerDefaults`は、指定のキーにデータを保存する機能ではなく、指定のキーにデータがない場合の初期値を設定する機能です。 データを保存するには`[defaults setObject:@"data" forKey:@"key"]`を使います。 もし誤解されていたのであれば、NSUserDefaultsの仕様を再確認した上でコードを再検証することをお勧めします。 次に前回の質問ですが、UUIDというのは確かに全ての端末で重複しないことを保証している訳ではないのですが、重複することはないという前提で設計しても問題ないくらいの重複率となるよう設計されたIDです。 (参考) 次にidentifierForVendorというのは、絶対変わらないのではなく、同一ベンダーのアプリを全て削除した後再インストールしたら変化することを理解していますか?(再インストールではなくアップデートであれば変化しません) (参考) この仕様から、自社アプリを複数インストールしているテスト端末では、テストアプリを何度再インストールしてもidentifierForVendorは変わらず、その会社のアプリを1個しかインストールしてない一般ユーザーは再インストールによりidentifierForVendorが変わるということになります。 また、参考URLに書かれているように、すぐに再インストールした場合は変わらない場合もあるようです。 こういう事態が発生している可能性はないですか? ちなみに、前回の質問のコメントで「違うUUIDが返ってきたとしても、UserDefaultsに保存されたデータを選択する、という動きをしているはずです」と書かれていますが、アプリを再インストールしてidentifierForVendorが変化した場合はUserDefaultsに保存したデータも初期化されていますが、それでちゃんと動作できますか? 最後に、(AppStoreのバグにより)アプリをアップデートしただけで変化する場合も過去にはあったようなので、 を参考に見ておいてください。