質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Q&A

解決済

1回答

4258閲覧

UserDefaultsが読み込めない(かもしれない)挙動について

takaki.satou

総合スコア21

Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

0グッド

0クリップ

投稿2016/02/03 14:05

編集2016/02/04 09:43

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)を流用しています。これも引継ぎ時には既にあった記述ですが、前後の記述を見る限り『毎回記述をする必要性』は無いと感じています。

アプリを完全に削除でもしない限り、この値は永続的に使用できる(はず) その根拠は?

こちらも「そういうものだ」という認識でした(引継ぎ時の組み方から判断して)。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Stripe

2016/02/03 14:12

>[defaults registerDefaults:dict]で保存。 何を保存してるんですか?
Stripe

2016/02/03 14:16

>既にデータがある場合は更新されない(はず) その根拠は?
Stripe

2016/02/03 14:22

毎起動時に新規にKeyを生成しているんですか?
Stripe

2016/02/03 14:23

>アプリを完全に削除でもしない限り、この値は永続的に使用できる(はず) その根拠は?
takaki.satou

2016/02/04 10:13

追加・修正依頼について、記事内に追記させていただきました。ご確認くださいませ。
guest

回答1

0

ベストアンサー

今回の質問の説明はStripeさんがコメントされているように謎だらけなのですが、前回の質問の説明と合わせて読んで、なんとか理解できたので気になった点をコメントします。

まず今回の質問の説明で「[defaults registerDefaults:dict]で保存」と書かれていますが、registerDefaultsは、指定のキーにデータを保存する機能ではなく、指定のキーにデータがない場合の初期値を設定する機能です。
データを保存するには[defaults setObject:@"data" forKey:@"key"]を使います。
もし誤解されていたのであれば、NSUserDefaultsの仕様を再確認した上でコードを再検証することをお勧めします。

次に前回の質問ですが、UUIDというのは確かに全ての端末で重複しないことを保証している訳ではないのですが、重複することはないという前提で設計しても問題ないくらいの重複率となるよう設計されたIDです。
(参考)
http://d.hatena.ne.jp/satosystems/20140123/1390460471

次にidentifierForVendorというのは、絶対変わらないのではなく、同一ベンダーのアプリを全て削除した後再インストールしたら変化することを理解していますか?(再インストールではなくアップデートであれば変化しません)
(参考)
http://qiita.com/ashdik/items/1ecbcbddf6ae476bd253#2位-uidevice-currentdeviceidentifierforvendor-uuidstring

この仕様から、自社アプリを複数インストールしているテスト端末では、テストアプリを何度再インストールしてもidentifierForVendorは変わらず、その会社のアプリを1個しかインストールしてない一般ユーザーは再インストールによりidentifierForVendorが変わるということになります。
また、参考URLに書かれているように、すぐに再インストールした場合は変わらない場合もあるようです。
こういう事態が発生している可能性はないですか?
ちなみに、前回の質問のコメントで「違うUUIDが返ってきたとしても、UserDefaultsに保存されたデータを選択する、という動きをしているはずです」と書かれていますが、アプリを再インストールしてidentifierForVendorが変化した場合はUserDefaultsに保存したデータも初期化されていますが、それでちゃんと動作できますか?

最後に、(AppStoreのバグにより)アプリをアップデートしただけで変化する場合も過去にはあったようなので、
https://teratail.com/questions/24053
を参考に見ておいてください。

投稿2016/02/03 17:08

編集2016/02/03 17:17
TakeOne

総合スコア6299

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takaki.satou

2016/02/04 10:13

TakeOneさま、ありがとうございます。 ご指摘の通りあまりにも把握できておらず、また乱文にて大変失礼いたしました。 ご丁寧にご指摘・ご指導いただき、感謝しております。 ご質問・ご指摘頂いた点、回答です。 ※質問にも追記させていただいておりますので、併せてご覧くださいませ。 > 指定のキーにデータがない場合の初期値を設定する機能です。 説明が明確ではありませんでした。私も同じように認識しておりました。 > こういう事態が発生している可能性はないですか? ユーザー様が削除後、再インストールされるケースは確かにあると思います。また、その場合はデータが消えてしかるべきなので、それで良いのですが…。 同一Venderアプリが1つのみの挙動については、把握はしていましたが、実際ご指摘されるまで、その環境を再現したテストをしておりませんでした。 試してみたいと思います。 > UserDefaultsに保存されたデータを選択する、という動きをしているはずです こちらは「もしかしたらアップデートでもUUIDが変わることがあるんじゃないか」という疑問に基づくものです。ご指摘のApple社のバグにより、それが発生することがある、ということも把握しておりました。 しかし、数回同じようなFeedbackを頂く方もいらっしゃいます。前回のアップデートは10月で、今回1月にもアップデートしています。Apple社のバグはすでに影響範囲外かと思いました。 取り急ぎ、ご確認いただいたところの、回答をさせていただきます。 お忙しい中ありがとうございました。
TakeOne

2016/02/04 14:45 編集

返信ありがとうございます。一点だけとても気になる点があります。 >>[defaults registerDefaults:dict]で保存。 >Keyとして生成された文字列を、Dictionary型 dictに代入後、上記の記述によりdefaults(NSUserDefaults)に保存(というより初期値設定)しています。 相変わらずregisterDefaultsで「保存」しているように書かれているのがとても気になります。 registerDefaultsは保存ではない(NSDefaultsファイルの内容を何も書き換えない)ということを理解されていますか? registerDefaultsはファイルの書き換えは何もせず、ファイルに指定キーのデータがなかった時のstringForKey返却値(初期値)を設定しているだけです。 例えば、 1.identifierForVendorでUUIDを取得 2.そのUUIDをregisterDefaultsで登録 3.stringForKeyでUUIDを読み込んで使用 としている場合、 アプリを再起動後、仮にidentifierForVendor返却値が変化した場合、 ファイルにUUIDを保存しているので、使用するUUID(stringForKeyが返却する値)は前回(最初に)取得したUUIDとなるよう設計されているように聞こえるのですが、実際にはファイルは何も保存されていないので、この場合、使用するIDは新しいUUIDに変わります。 本来は 1.stringForKeyでUUID取得 2.データなし(nil)だったら、identifierForVendorでUUIDを取得し、それをsetObject:forKeyで保存 3.取得したUUIDを使用 とすべき処理のように思えますがいかがでしょうか? この方法でやるなら、そもそもidentifierForVendorのようにUUIDがベンダー内で一定であることを求める必要もないので、[NSUUID UUID]でUUIDを取得してもよいと思います。
takaki.satou

2016/02/05 13:21

TakeOneさま ご返答頂き、ありがとうございました。 再びご指摘の点を確認させていただき、ようやく原因の特定に至りました。 やはり再三のご指摘の通り、「registerDefaults」を『保存している』と誤解している所に問題があったようです。 リリースVer.のUserDefaultsには、KeyとなるべきIDが保存されておりませんでした。 ご提案の処理についてもごもっともでございます。 早速、そのように処理を変更させていただきました。(←UserDefaultsからデータが正しく読み出せました!!) [NSUUID UUID]についても確かにその通りなのですが、今回不具合報告が一部に限られていたのも、複数アプリをインストールして頂いていたのでは、と考えています。なので、少なくとも次のアップデートまでは(この不具合を収拾するまでは)ForVenderを使用したいと思います。 見返せば、最初から丁寧にご指摘頂いていたのに(しかもすごく初歩的な点を…)、自分の理解を優先する傲慢さに恥じ入るばかりでございます…。 ともあれ、これで不具合(というより仕様不備)は解決できそうです! ありがとうございました!!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問