ある記録をRDB的に保管し、後に参照や集計をしたい。objective-cでそれを実現するために、CoreDataを使って実装している。
ここでは、CoreDataの概念を自分なりにまとめた結果と、次回似たような作業する際につかう覚書を残しておく。
CoreDataの主要な仲間たちを整理する
数名の関係者が協力しあって、アプリとデータストアとの相互作用を実現している。
(仲間たち、っていうのは僕の語彙不足による悲しい表現方法ですが、もっとちゃんとした名称って日本語でどう言えばいいのだろうか。ちなみに参考にした英語サイトでは、Core Data Stackと表現している)
CoreData | 役割・概念 |
---|---|
Managed Object Model | アプリで利用するスキーマ(DBスキーマみたいな) |
Persistant Store Coordinator | 永続化ストア(デフォルトはSQLite)との調整役 |
Managed Object Context | アプリがデータと相互作用するために利用するスクラッチパッド |
CoreDataに関する関係性の理解には、下記がわかりやすい。
以下、自分がわかるような言葉でまとめる。
- Managed Object Modelはxcdatamodeldにて視覚的に定義
- Managed Object Contextを介して、情報を操作することが基本原則
- Persistant Store Coordinator以降の低層のことは、AppDelegateがある程度面倒みてくれるので今は気にしない
- manage Object Context はスクラッチパッド(情報の一時保管領域)なので、明示的な更新や保存が必要
実装中に気づいたことや時間がかかったこと
CoreDataのモデルオブジェクトをalloc
してもエラーになる
当初、アプリのモデルオブジェクトは便宜的にNSMutableArrayで実現していたため、初期化は[[NSMutableArray alloc] init]
で行っていた。
その後、このモデルオブジェクトをCoreData用にカスタマイズしていく過程で、エラーが発生した。
http://stackoverflow.com/questions/14671478/coredata-error-failed-to-call-designated-initializer-on-nsmanagedobject-class 'Entitiy'
これによると、
NSObjectの初期化はalloc/initでもちろんOKだが、NSManagedObjectを初期化するには initWithEntity:insertIntoManagedObjectContext
でないとダメ。
今回のような過程では、プロパティ、インスタンス変数、ローカル変数の全てでちゃんと手直ししないといけない。ちなみにコンパイルは通る。
永続化ストアコーディネイタを作成できない
原因は、xcdatamodeldの名前をAppDelegate.mに記載していないからだった。記載していたのは、モデルクラスの名前だったのでこれが問題。
ここを読んで解決した。
途中でモデルの内容を変更すると動かなくなる
エディタを使って気軽に手軽にカラム追加、型変更できると思っていたら違った。
一定の手続きが必要であり、それはここを参考にさせていただいた。
アプリリリースとかする前なら、もっとお手軽に修正する策はあるはず!と密かに思っているが、今の時点では調査できていない。
CoreDateでgroup by
する時の基本方針
選択列、集計キーや計算方法を定義して、NSFetchRequestObjectのプロパティとして設定する。SQLと比べるとはるかに多いコード量(と思うのは僕だけ?)
下記はとても参考になったサイト
http://mattconnolly.wordpress.com/2012/06/21/ios-core-data-group-by-and-count-results/
label.textに数値を入れるときには、NSNumber stringValue
を使う
これは見出しの通りで、そうしないとエラーになる。