以前、書いたようにブログ書き支援用の小アプリを作る。
Cocoaの日々: SimpleCapへ Webページのスクリーンショット機能を追加する(予定)
HTMLのAタグとサムネイル画像を作るようなアプリを考えている。名前は BlogAssistant にしよう。このデータを CoreData で管理させようと思っていろいろ試行錯誤している。今回は簡単なモデルを作成し、それを NSTableView へ表示させてみよう。
Xcodeで Core Data Application を作成する
(以下、MacOSX10.5、XCode 3.1.1で操作)
新規プロジェクトを作る。後々 Safariのプラグインに変える予定だが CoreDataの挙動を確認しながら作りたいのでまずは単体のアプリケーションとして作る。Xcodeで新規プロジェクトを作成しテンプレートの中から Core Data Application を選択する。
自動的に *_AppDelegate クラスが生成される。
このクラスにはあらかじめ Core Data 永続化スタックを使うのに必要なコードが自動的に用意されている。ヘッダファイルはこんな感じ。
BlogAssistant_AppDelegate.h
#import
@interface BlogAssistant_AppDelegate : NSObject
{
IBOutlet NSWindow *window;
NSPersistentStoreCoordinator *persistentStoreCoordinator;
NSManagedObjectModel *managedObjectModel;
NSManagedObjectContext *managedObjectContext;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator;
- (NSManagedObjectModel *)managedObjectModel;
- (NSManagedObjectContext *)managedObjectContext;
- (IBAction)saveAction:sender;
@end
これをベースに作って行こう。
モデルの定義
*.xcdatamodel を開いてデータモデルを定義する。エンティティ Homepage をこんな感じで作ってみた。
併せてモデルクラスを用意する。
新規ファイルを作成し、属性をプロパティ定義していく。このあたりXCodeが自動生成してくれると良いのだが(何か方法があるのだろうか?)。
Homepage.h
#import
@interface Homepage : NSManagedObject {
}
@property (retain, nonatomic) NSDate * createdDate;
@property (retain, nonatomic) NSString * imageName;
@property (retain, nonatomic) NSString * memo;
@property (retain, nonatomic) NSDate * modifiedDate;
@property (retain, nonatomic) NSString * title;
@property (retain, nonatomic) NSString * url;
@end
Homepage.m
#import "Homepage.h"
@implementation Homepage
@dynamic createdDate;
@dynamic imageName;
@dynamic memo;
@dynamic modifiedDate;
@dynamic title;
@dynamic url;
@end
@dynamic 指定している件については以前のブログを参照されたし。
Cocoaの日々: CoreData - NSManagedObject のプロパティ
テーブルビューの用意とバインディング
InterfaceBuilder を立ち上げ、ウィンドウへテーブルビューを配置する。
続いてモデルとビューの橋渡しを行う NSArrayController を MainMenu.xib へ追加する。
インスペクタを開き、Attributes を編集する。
変更点は下記の通り:
- Mode を Entity へ変更する
- Entity Name へ先ほど用意したモデルでのエンティティ名 Homepage を指定する
- Prepares Content にチェックを入れる(これで NSArrayController が自動的に NSManagedObjectContext 経由で保存データを読み込んでくれる)。
次にテーブルビューのカラムを選択した後、NSArrayController へバインドする。
Controller Key へ arrangedObjects を、Model Key Path に title(カラムに表示するモデルの属性)を指定する。
他のカラムも同様にバインドしておく。
ここまででコントローラー(NSArrayController)とビュー(NSTableColumn)とのバインドができた。後はコントローラとモデルの紐付けが必要。NSArrayController は(親クラスの NSControllerは)CoreDataをサポートしていて -[setManagedObjectContext:] がある。これを使ってコントローラとモデルを結びつける。
参照:Mac Dev Center: NSObjectController Class Reference
BlogAssistant_AppDelegate.h
@interface BlogAssistant_AppDelegate : NSObject
{
:
IBOutlet NSArrayController *arrayController;
}
ヘッダへアウトレットを一つ追加し、InterfaceBuilderでNSArrayController へ接続する。
最後に NSArrayController へ NSManagedObjectContext を設定する。これは今回コードで書く。
BlogAssistant_AppDelegate.m
- (void)awakeFromNib
{
[arrayController setManagedObjectContext:[self managedObjectContext]];
}
これで Model-View-Controller が全てつながった。データの管理は NSManagedObjectContext が良きに?取りはからってくれる。
テスト用ボタン追加
表示を確認するにはテストデータが必要。テストデータを追加するボタンを付ける。
ボタンのターゲットは BlogAssistant_AppDelegate とし、アクションは addTestRecord: につなぐ。実装はこんな感じ。
BlogAssistant_AppDelegate.m
- (IBAction)addTestRecord:(id)sender
{
Homepage* homepage = [NSEntityDescription insertNewObjectForEntityForName:@"Homepage"
inManagedObjectContext:[self managedObjectContext]];
homepage.title = [NSString stringWithFormat:@"TEST TITLE:%@", [[NSDate date] description]];
homepage.imageName = @"TEST IMAGE";
homepage.url = @"http://xcatsan.com/";
homepage.createdDate = [NSDate date];
homepage.modifiedDate = [NSDate date];
homepage.memo = @"MEMO";
NSError* error = nil;
[[self managedObjectContext] save:&error];
if (error) {
NSLog(@"INSERT ERROR: %@", error);
} else {
NSLog(@"INSERTED");
}
}
保存形式を SQLite へ変更する
自動生成されたコードでは保存形式が XMLになっている。これを SQLへ変更する。
BlogAssistant_AppDelegate.m
- (NSPersistentStoreCoordinator *) persistentStoreCoordinator {
url = [NSURL fileURLWithPath: [applicationSupportFolder stringByAppendingPathComponent: @"BlogAssistant.db"]];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:&error]){
[[NSApplication sharedApplication] presentError:error];
}
}
動作確認
動かしてみよう。起動して何度かボタンを押してテストデータを生成する。
NSManagedObjectContext へ対するテストデータ追加がテーブルビューへ自動的に反映された。ダブルクリックすると変更もできる。
アプリを止めて再起動するとデータが復元される。
ここまでで MVCの連携コードを書いて InterfaceBuilder を設定しただけ。CoreDataとBindingsを使うと、ローカルDB付きのテーブルビューがこんなに簡単にできてしまう。
保存データ
さてデータはいったいどこに保存されているのか。自動生成されたコードを見るとライブラリ配下の Application Support にあるようだ。
url = [NSURL fileURLWithPath: [applicationSupportFolder stringByAppendingPathComponent: @"BlogAssistant.db"]];
ターミナルを開き sqlite3 コマンドで中身が確認できる。
ソースコード
github へ上げました。
BlogAssistant at master from xcatsan's SampleCode - GitHub
おまけ:SQLite のログ
実行時オプションにを -com.apple.CoreData.SQLDebug 1 付けるとデバッガコンソールへ SQLite のログを出力させることができる。
(参考)Cocoa Touch の日々: CoreData で発行されている SQL をデバッグ出力する
こんな感じ。
- - - -
BlogAssistant開発:続く..