- ベストアンサー
xcodeで配列を保存する方法を教えてください
- xcode初心者の方が、ボタンを押すと日付を取得して配列に保存するアプリを作成していますが、MutableArray変数の宣言方法に問題があり、データの保存や読み込みがうまくいっていません。解決策を教えてください。
- xcodeで配列を保存する方法についての質問です。日付を取得して配列に保存するアプリを作成していますが、MutableArray変数の宣言方法がうまくいっていないようです。どのように宣言すればよいか教えてください。
- xcodeで配列を保存する方法を教えてください。日付を取得して配列に保存するアプリを作成していますが、MutableArray変数の宣言方法がうまくいっていないためデータの保存や読み込みができません。解決策を教えてください。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
No.2のつづきです。 回答後、ちょっとしっくりこないところがあったので、テスト用のプログラムを改良して、もういちど確認したところ、mutableCopyしなくても、「objectForKey:」から読み出したArrayが、そのままMutableになることを確認しました。う~ん、いつのiOSのバージョンから、こうなったのだろう? NSUserDefaults Class Reference https://developer.apple.com/library/ios/documentation/cocoa/reference/foundation/Classes/NSUserDefaults_Class/Reference/Reference.html ここから引用: objectForKey: Returns the object associated with the first occurrence of the specified default. - (id)objectForKey:(NSString *)defaultName (中略) Special Considerations The returned object is immutable, even if the value you originally set was mutable. こう注記があります。 現在のコンパイラ(LLVM+Clang)では、Mutableになるからといって、将来のコンパイラでも同様にMutableになるという保証はありません。クラスリファレンスのこの注記が掲載される限り、それに従ったプログラムをすべきだと思います。
その他の回答 (4)
- Lchan0211b
- ベストアンサー率61% (573/930)
No.3です。 すいません。私もてっきりimmutableになるとばっかり思いこんでいました。 というか、これ配列の読み込みなのにarrayForKeyじゃなくてobjectForKey を使っていますね。 objectForKeyを使うなら、 http://lab.dolice.net/blog/2013/12/30/objc-ns-user-defaults-and-ns-data/ にあるように、NSKeyedUnarchiverでNSDataに変換して読み書きする必要があると 思っていましたが、このあたりも最近は変わったようですね。 もしかすると内部で自動的にNSDataへの変換をするように実装が変わったのかも しれませんが、API仕様書でimmutableだと言っている以上、immutable扱いで 処理すべきですね。 それと、No.3で意味不明の3行コードがあるので削除すべきだと コメントしましたが、これってもしかしてNSUserDefaultsに まだ何も書きこまれていない時の初期化の意味でやっているんでしょうか? だとしたら、ここで初期化するのではなく、viewDidLoadで [Rireki objectForKey:@"kitaku"]; をした直後にやるべきだと思います。 または、NSUserDefaultsには、まだ何も書きこまれてない時のデフォルト値を 登録する機能がありますので、objectForKeyで読み込む前に、 [Rireki registerDefaults:@{@"kitaku":@[]}]; と書いておけば、まだ何も書きこまれていない場合、_kitakuに初期化された配列 が格納されるようになります。他にもたくさん設定値があっていろいろな項目の 初期値を決めないといけない時は、registerDefaultsでまとめて初期値を登録して おくと便利です。
お礼
再度のご指摘、本当に有り難うございます。 初期化の話も含めて、どのセクションに何を書くべきなのかも曖昧な状態ですので、さらに勉強していきたいと思います。 大変勉強になりました。 有り難うございました。
- Lchan0211b
- ベストアンサー率61% (573/930)
> 私のコードでは最後にご指摘いただいたmutableCopyのような処理は入れておりませんが、 > ちゃんと_kitaku配列はinsert可能になっております。 > その辺り、どうして問題なく出来るのかご教示いただければ、幸いです。 確かに、質問に書かれているコードはinsertでエラーになりません。 だって、 [_kitaku insertObject:kitaku atIndex:0]; のinsertの前に if(!_kitaku){ _kitaku = [[NSMutableArray alloc] init]; } という、変な3行のコードがあるじゃないですか。 No.1さんの最初の指摘にある通り、NSDefaults読み込み処理は インスタンス変数の_kitakuじゃなくて、ローカル変数の _kitakuに読み込んでいます。だからインスタンス変数の_kitaku はnilのままです。 このため、GetTimeメソッドが呼ばれた時、インスタンス変数の_kitaku がnilなので、上述の3行コードにより新しいNSMutableArrayを生成して _kitakuに格納しています。それに対してinsertObjectしているの だからエラーにはなりません。 でも、本当はこんなことをやりたいんじゃないでしょ? たぶん、最初insertObjectをした時に_kitakuがnilだというエラーが 出て、読み込んだはずの_kitakuがなぜnilなのか、その原因がよくわからず とりあえずエラーにさせないよう安直に上述の意味不明コードを 入れたのではないかと思います。 このコードのせいで自分で自分を罠に陥れているということです。 No.1さんの最初の指摘を修正した上で、この変な3行コードを 削除してください。 そうすれば、No.2さんの回答通り、Mutableでない配列にinsertは できないというエラーが出るはずです。 それを確認したら、No.1さんの後半の指摘通り修正してください。
お礼
Lchan0211b様。 的確なご指摘有り難うございます。 ご推察の通り、謎の3行はあまりよくわからずエラー回避のために入れていました。 皆様のご指摘ふまえ、あるべき姿に修正頑張ろうと思います。
- harawo
- ベストアンサー率58% (3742/6450)
> いただいたコメントの最後の部分でアドバイスいただいた内容ですが、私のコードでは最後にご指摘いただいたmutableCopyのような処理は入れておりませんが、ちゃんと_kitaku配列はinsert可能になっております。 じっさいに、NSUserDefaultsから読み出した、NS(Mutable)Arrayインスタンスに、要素をインサートしようとしたら、下記のエラーが出ました。 2014-09-02 19:45:51.300 DefaultsTest[2866:60b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object' Immutableなオブジェクト(Array)にMutableなメソッドを送ったという、「期待どおりの」エラーメッセージです。 > その辺り、どうして問題なく出来るのかご教示いただければ、幸いです。 「問題なく出来る」プログラムを見せてください。そうでなければ、検討のしようがありません。
- harawo
- ベストアンサー率58% (3742/6450)
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib.(みっともないから、このコメント文は削除しようぜ) // 保存した時間を読み込む NSUserDefaults *Rireki = [NSUserDefaults standardUserDefaults]; NSMutableArray *_kitaku = [Rireki objectForKey:@"kitaku"]; // ? _kitaku = [Rireki objectForKey:@"kitaku"]; // ブレークポイント NSLog(@"過去結果配列 %@",_kitaku); } インスタンス変数の_kitakuとはべつのNSMutableArray *_kitakuを作っちゃうと、まずいでしょう。 蛇足: NSUserDefaultsに、Mutableなオブジェクトは保存できません。保存して、読み出したら、Immutableなオブジェクトになっています。なので、読み出す都度、「mutableCopy」するか、「[NSMutableArray arrayWithArray: savedArray];」こんな処理が必要になるでしょう。
お礼
harawoさん、早速の回答ありがとうございました。 おかげ様で、問題解消しました。 まだ変数のことがよくわかっていないようで、もっと精進します。 本当にありがとうございました。
補足
harawoさま いただいたコメントの最後の部分でアドバイスいただいた内容ですが、私のコードでは最後にご指摘いただいたmutableCopyのような処理は入れておりませんが、ちゃんと_kitaku配列はinsert可能になっております。 その辺り、どうして問題なく出来るのかご教示いただければ、幸いです。 よろしくお願いいたします。
お礼
harawo様。 いろいろ確認頂き、本当に感謝しております。 自分のコードが、たまたまインサート可能になっていたこともよくわかりました。 今後もちゃんとアプリが動くように、規定にそったコードに直していきたいと思います。 この度は、私の拙い質問に、迅速にレスポンス頂き感謝しております。 他にもコメント頂いた方もいらっしゃり、皆様に感謝しておりますが、 まっさきに回答いただきましたharawoさんをベストアンサーにさせていただきました。 どうも有り難うございました。