CoreDataを使っていて、リレーションなどごちゃごちゃやって、関連するデータを取り出してみたら、そのデータがソートされていない。単純にDBに保持されているものを持ってくるだけだから、並び替えしていないってことで、自前で並び替えなければならない。SQLが使えれば楽なのに。。。

で、調べてみたので、残しておく。

※ 下記ソースの簡単な説明として、CoreDataから1つのteamDataを取得し、それに紐付くNSSet型のmembersのデータ(Member *)を、複数の条件で並び替えすることを想定している。

// CoreDataのリレーションで関係づけられたデータは、NSSet型で保存される.

NSSet *members = teamData.members;


// ソートする条件を指定。

NSSortDescriptor *sort1 = [NSSortDescriptor

                           sortDescriptorWithKey:@"memberNo"

                           ascending:YES] ;

NSSortDescriptor *sort2 = [NSSortDescriptor

                           sortDescriptorWithKey:@"activeFlag"

                           ascending:NO] ;


// ソートする条件を配列で保持。

NSArray *sortDescriptors = [NSArray arrayWithObjects:

                            sort1,sort2,nil];

// NSSet型のmembersをソートして配列membersArrayに保持。

NSArray *membersArray = [members sortedArrayUsingDescriptors:

                         sortDescriptors];


// 結果を見てみよう。

for (Member* memberData in membersArray) {

    NSLog(@"memberData   %@ %@",

               memberData.memberNo,

               memberData.activeFlag);

}


これで並び替えができているはず。(ただし、このソースはサンプルで、実際にコンパイルはしていないので悪しからず)

また、もしソート条件が1つだけの場合には、arrayWithObject: を使えばよい。複数の場合の arrayWithObjects: は最後の"nil"が大事。忘れてコンパイルが通らなくて焦った。

NSArray *sortDescriptors = [NSArray arrayWithObject:sort1];



PHPだったらsortOn("memberNo"); とかやればいいので便利だけど、Objective-Cはまだ慣れない。。。


普通にDBを使っていて、プライマリキーとかユニークキーとか当たり前に使うものだと思っていたけど、CoreDataを利用するにあたってはその概念が当てはまらない。とはいえ、SQLiteをラップしているので、裏側ではちゃんとプライマリキーとか持っているようだが、表だって使うことができないのだ。

でもいろいろなviewを行き来するのに、そのテーブル(エンティティ)内の一意のデータのキーを持ちまわるのが妥当と判断したため、どうしても PRIMARY KEY に AUTO INCREMENT を設定したカラムを使いたかったのだが、いろいろ調べた結果、直接、PRIMARY KEY も AUTO INCREMENT も使うことができないことが判った。(実は良い方法があるのかもしれないが、そこまでCoreDataを熟知していない。SQLiteを直接実行する方法もあるのかな?)

で、もっと調べて、代わりに利用できそうなのが NSManagedObjectID である。これは、TableView(っていうかfetchedResultsController) で利用される indexPath と似ているので理解が早い。


使い方は簡単。
まず最初に、取得した ManagedObject から objectID を保持。
 
NSManagedObjectID *objID = [managedObject objectID]; 

NSLog(@"entryID == %d", objID );

 
保持した objectID を使って、managedObjectContext から目的の ManagedObject を取り出す。

NSManagedObject *managedObject

           = [managedObjectContext objectWithID:objID];


とりあえず、これで目的の挙動の代用とすることができる。

ただ、この objectID の注意点としては、 AUTO INCREMENT のように1からの連番ではないということ。
また、コンパイル毎に違う数字が返される。ってことは、DB上で持っている数字ではなく、システムで与えられる数字なのだろう。この点は TableView で利用される indexPath も同じことが言える。

 

まだまだ勉強中のため、間違いがあればご指摘ください。

CoreDataの勉強中でまだまだ自分のものにできていないのだが、そんな自分の強力なサポートとして、CoreDataの発行するSQLをデバッグログに表示してくれる方法がある。

ずいぶん前に設定したのだが、新しいプロジェクトに設定するのに忘れないよう残しておく。

まずは「プロジェクト」タブの一番下「アクティブな実行可能ファイル・・・」を選択。

screenshot_1.png

「引数」タブの「起動時に渡される引数」に下記のコードを追加。

-com.apple.CoreData.SQLDebug 1

screenshot_2.png
下の変数はデバッグ用のコード。

これでコンソールにCoreDataのログが出力される。

[31597:207] CoreData: sql: BEGIN EXCLUSIVE

[31597:207] CoreData: sql: SELECT Z_MAX FROM Z_PRIMARYKEY WHERE Z_ENT = ?

[31597:207] CoreData: sql: UPDATE Z_PRIMARYKEY SET Z_MAX = ? WHERE Z_ENT = ? AND Z_MAX = ?

[31597:207] CoreData: sql: COMMIT

[31597:207] CoreData: sql: BEGIN EXCLUSIVE

[31597:207] CoreData: sql: SELECT TBL_NAME FROM SQLITE_MASTER WHERE TBL_NAME = 'Z_METADATA'

[31597:207] CoreData: sql: DELETE FROM Z_METADATA WHERE Z_VERSION = ?

[31597:207] CoreData: sql: INSERT INTO Z_METADATA (Z_VERSION, Z_UUID, Z_PLIST) VALUES (?, ?, ?)

[31597:207] CoreData: sql: INSERT INTO ZBOOK(Z_PK, Z_ENT, Z_OPT, ZTITLE, ZWRITER) VALUES(?, ?, ?, ?, ?)

[31597:207] CoreData: sql: COMMIT

[31597:207] CoreData: sql: pragma page_count

[31597:207] CoreData: annotation: sql execution time: 0.0018s

[31597:207] CoreData: sql: pragma freelist_count

[31597:207] CoreData: annotation: sql execution time: 0.0012s

2011年2月

    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28          

最近のコメント

アイテム

  • screenshot_1.png
  • screenshot_2.png
  • mzl.jpqumane.480x480-75.jpg
Powered by Movable Type 5.02