Study CoreData 1 ~時をさかのぼる 前編~

さて、CoreData Study 第二回目です!
 
今回は、Xcodeで自動生成されたCoreDataの処理内容をざくっと見ていくことにしましょうか。
 
ってコトで、いきなり本題に入ります。
 
まずは起動時にどのような処理が行われているかを見てみましょう。
こういった初めて見るコードがどのように繋がっているのかを調べていくには、時間軸をさかのぼってコードを見ていくのが分かりやすいんじゃないかなぁと思います。
 
なので、まずはUITableViewのCellを生成しているメソッドから見ていくことにします。

注意:投稿者自身もCoraDataについて勉強中のため、このシリーズには誤りが含まれている可能性があります。もし、間違いに気付かれた方はコメント欄もしくはtwitterなどでご指摘いただけると幸いです<(_ _)>
また、開発環境はXcode3.2.3 iPhone SDK 4です。実機でのテストなどは自己責任でお願いいたします。

 
 
1. UITableViewCellのデータ情報の出どころを探る
 
UITableViewを使ったコトのある方なら既にご存知の通り、UITableViewのCellの見た目や表示するデータを指定するメソッドは [tableView:cellForRowAtIndexPath:]になります。
 

 
そこに、[self configureCell:cell atIndexPath:indexPath];という見慣れないメソッド呼び出しがあります。
メソッド名からして
“渡されたindexPathによって、cellの構成をする”
ってな感じでしょうか?

では、⌘を押した状態でこの“configureCell”の部分をダブルクリックしてみます。
すると、このメソッドの実装部が表示されました。
 

で、ここで何をしているかと言うと、

1. <self.fetchedResultsController>の中のindexPathに対応する『何か』を、<NSManegedObject>のインスタンスオブジェクト<managedObject>に代入する。
2. managedObjectの中の<timeStamp>というKeyに対応する値を文字列にして、cellのテキストラベルに表示させる。

という感じっぽいですが、ワケワカメ…???
 
なので、もっと分かりやすくざっくりと説明してみます。
(このエントリー自体がざっくりですが…^^;)
 
 
まず、[managedObject valueForKey:@”timeStamp”]の部分から。
これがよく目にするキー値コーディング(KVC:Key-Value-Cording)というヤツらしいです。
 
 
2. キー値コーディングとは
 
例えば、UIButtonが2つあってそれぞれにKeyに対応するValueを設定したとします。
(※ここでは分かりやすくするためにUIButtonとViewで説明しますが、実際にはKVCに対応したクラスでのみ使うことができます。)

[buttonA setValue:@"A" forKey:@"buttonName"];
[buttonB setValue:@"B" forKey:@"buttonName"];

この2つのボタンは共に同じKey(@”buttonName”)に対応するValueを持った事になります。
そこで、この2つのボタンのどちらかから何らかのアクションを受け取ったときに、その送ったボタン(sender)がどちらかなのかを調べたい時に以下のように使えます。

- (void)actionFromButton:(id)sender {
 NSString *buttonNameValue = [sender valueForKey:@"buttonName"];
 //buttonNameValueにはAかBが入れられる
}

 
さらに、このふたつのボタンが同じView(contentView)にaddSubviewされていたとします。

UIButton *button = (UIButton *)[contentView.subviews valueForKeyPath:@"buttonName.A"];
// buttonにはbuttonAが入れられる

こうして[valueForKeyPath:]Keyの後ろに[.]を付けてその後にValueを指定する事で『Key(@”buttonName”)のValueが@”A”のオブジェクトを返す』みたいな事が出来るようになります。

これは使いどころによってはかなり便利なんじゃない!?…ってのがKVCです。
(何度も言いますがかなりざっくりです!^^;)
 
 
3. CoreDataのデータオブジェクト

つまり逆に考えると、[managedObject valueForKey:@”timeStamp”]としているからには@”timeStamp”というKeyに対応するValueが<managedObject>には設定されているってことになりますね。
 
 
んじゃ、そのValueを持ってる<managedObject>ってナニモン??
って感じで次の壁にぶち当たるワケです。
 
このmanagedObjectは、<NSManegedObject>クラスのオブジェクトですね。
で、<NSManegedObject>はどんなクラスかを調べるために、今度は<option>キーを押しながらNSManegedObject部分をダブルクリックしてみます。
 

 
マネージドオブジェクトってことは「管理されたオブジェクト?」
Abstractに<Core Data model object.>とあるように、CoraDataのデータオブジェクト。
つまり、データそのものってことなんですかねぇ…。

では、そのデータをどこから取ってくるのかと言うと…

NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];

<self.fetchedResultsController>に、テーブルビューセルのindexPathを渡すと取得できるようです。
 
 
4. NSFetchedResultControllerのプロパティ

それで、今度は<fetchedResultsControllerプロパティ>の実装を見てみます。
(かなり複雑で読むのが大変かもしれませんので、切りのいいところで一休みしてくださいね。)
 

(長っ!!)
 
まず始めにさっきと同じように<NSFetchedResultsController>のAbstractを調べてYahoo!翻訳(^〜^;)してなんとなく意訳してみるとこんな感じでしょうか?

このクラスは、CoreDataフェッチリクエストから返されるデータを、能率的でUITableViewで扱いやすいオブジェクトとして提供するためのクラスです。

 
つまりCoraDataをテーブルビューで扱うための便利ツールってことみたい。
 
この中にある”フェッチリクエスト”とは、書籍などでは『あらかじめ定義されたクエリのようなもの』という感じで書かれているんですが、簡単にいうと『データを取り出すための条件』って感じだと思います。
 
 
5. フェッチリクエストは良いヤツ?
 
分かりやすくするために、Macのスポットライト検索で例えてみましょう。
 

(やけにダブったファイルが…^^;)

上の画像だと
『”このMac”の中から内容に”CoreData”が含まれる、かつ”種類”が”PDF”のものを探す』

つまり、フェッチリクエストとはこの検索条件のようなものかと。
(まぁ、正確には違いますが、感覚として。)
 
 
『リクエスト』とあるように、もっと意訳してしまうと、

色々持ってる『CoreDataオブジェクトな彼』に、

『アナタの持っているモノの中で『一番高くて貴重なもの』をわたしにちょーだいっ!なければいらないっっ\(>o<)/』

 
という言いたくても中々言えないわがままを、代わりに言ってくれるのがフェッチリクエストなんぢゃないかなぁと。
フェッチリクエストって良いヤツ…
 
 
 
……スミマセン…脱線しました…<(_ _;)>…
 
 
6. 様々な登場人物で舞台を作り上げる。

でわ、気を取りなおりして(^^;)アクセサメソッドの中身を見ていきましょう。

if (fetchedResultsController_ != nil) {
    return fetchedResultsController_;
}

これは、そのままですね。
fetchResultControllerがあればそれを返して、この下に書かれた処理はしない。
 
つまり、fetchedResultsControllerがまだ作られていない(もしくはnillの)場合のみ、これ以下の処理をさせる事になります。
当然これから下の処理でfetchedResultsControllerが作られます。
 
 
ここでは(ちょっと疲れてきたので…)思い切って、インスタンス変数などを実際の物や人に置き換えて考えてみます(笑)
逆に分かりづらくならないと良いのですが…

NSFetchRequest *fetchRequest = [[NSFetchRequestalloc] init];

まず、誕生するのが例の”良いヤツ”フェッチリクエストです。
フェッチリクエストは良いヤツですが『誰に何を頼んでほしいのか』をリクエストしてあげないと、自分では何も出来ないちょっと引っ込み思案なところもあるようです。

なのでリクエストをしてみます。

NSEntityDescription *entity =
 [NSEntityDescription entityForName:@"Event"
      inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];

この中の<NSEntityDescription>『何をリクエストするのか?』にあたります。

例えば、『彼』色々なブランドのバッグそれぞれたくさん持っているとして、
各バッグをひとつのデータだとすると、『ブランド』が<NSEntityDescription>にあたる感じ。
(超意訳^^;)
 
つまり、ここでは

『<self.managedObjectContext>が持っている@”Event”ってブランドのものを…』

ってことをフェッチリクエストにまず教えてあげます。
(managedObjectContextについては後述します。)
 
で、次の

// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];

ですが、ごめんなさい<(_ _)>これはちょっと不確実なのですが、
一度に表示される各データオブジェクトの数(テーブルビューならセルの数?)にプラスαした数をこの数値に入れると良いようです。
 

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timeStamp" ascending:NO];

そして今度は<NSSortDescriptor>という仕事人が登場します。
ソートデスクリプター!強そうです。タイムスタンプ持ってます!

どんな仕事人かというとソート(並べ替え)の達人です。
フェッチリクエストがもらってきたものをキレイに指定した順番どおり並べてくれます。

なので、この達人に並び替える条件を教えてあげます。
この場合はKey(@”timeStamp”)の値が大きい順番(ascending:NO)に。という条件です。
(※[ascending:]にYESを渡すと昇順。NOなら降順になります。)

ただ、この仕事人はかなり頑固なのでひとつの条件でしか並び替えてくれません。
なので、他の条件のソートもお願いしたいなら、別の達人を用意します。

例えばこんな場合です。

『まず値段の高い物順に並べて、同じ値段のものがある場合は新しいものを先に並べる』

 
その場合は、<NSSortDescripter>にチームを組ませて<sortDescriptors>として力を合わせて協力させます。
ただし、今回は一人の達人で充分なのでひとりで<sortDescriptors>としてがんばってもらいましょう。
 
そしてフェッチリクエストが持ってきたものを渡せるように、フェッチリクエストに<sortDescriptors>の存在を教えておきます。
(フェッチリクエストにこの達人チームを教えておかないと、せっかくデータを持ってきてもめちゃくちゃな順序のデータになってしまいます。)

NSArray *sortDescriptors = 
 [[NSArray alloc] initWithObjects:sortDescriptor, nil];
 
[fetchRequest setSortDescriptors:sortDescriptors];

 
 

…と、ここでやっと役者が揃ったので、
このドラマ(?)の主役!!
<NSFetchedResultsController>さんに登場して頂きます!

 
 
(長くなったので後編につづく:18:30頃公開)

広告

Study CoreData 1 ~時をさかのぼる 前編~」への1件のフィードバック

  1. ピンバック: [朝刊] 池上彰さんの人気が高騰しています。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中