Navigation-based Applicationテンプレートを選ぶ場合はCore Dataを使うかどうか選択できるようになってるけど、View-basedではチェックボックスが出てこない。
それならば自分で実装しようということになるのだけれど、うーんうーんって感じになる場合が多いと思うの。
なので手順を書いておく。
Xcode 3.2.4 and iOS SDK 4.1 で試してる。
古いバージョンとか新しいバージョンのこと考えてない。
新規プロジェクトをView-based Applicationを選択して名前をMyCDataとして作成してます。
僕がやったポイント。
- CoreData.frameworkを追加
- DataModel(.xcdatamodel)ファイルを新規作成
- DataModelにエンティティ作ってプロパティを追加
- .xcdatamodelを.xcdatamodeldにバンドル
- Managed Object Class(NSManagedObjectサブクラス)ファイルを新規作成
- おまじないのコード(NSManagedObjectContextなどを用意)
- 後は普通にコード書く
- データの読み込みや追加などは、用意したコンテクスト(NSManagedObjectContext)を通じて実行
1.Frameworksグループを右クリック>追加>既存のフレームワーク>CoreData.frameworkを追加
2.Resourcesグループを右クリック>追加>新規ファイル>DataModelを選択>MyCData.xcdatamodelと名前付けて次へでそのまま完了。
3.MyCData.xcdatamodelにエンティティPersonを追加して、そのプロパティにageとnameを追加。
データ型を
age は Int16
name は String
とした。
4.MyCData.xcdatamodelを選択した状態で、設計>データモデル>モデルバージョンを追加。
MyCData.xcdatamodeldにMyCData.xcdatamodelがバンドルされた形になる。
MyCData.xcdatamodeldの中にxcdatamodelファイルが1つ追加されるけどいらないので削除する。
※この4.をやらないで対応する方法もあるけれどそれは書かない。将来的にモデルの変更(プロパティの追加など)がされる可能性を考えれならこれやっとけばいいじゃん、必要になるでしょってことで。
5.エンティティPersonを選択した状態でファイル追加をするとManaged Object Classが選べるので、そのまま完了するとPerson.h/.mが追加される。
//
// Person.h
//
#import <CoreData/CoreData.h>
@interface Person : NSManagedObject
{
}
@property (nonatomic, retain) NSNumber * age;
@property (nonatomic, retain) NSString * name;
@end
//
// Person.m
//
#import "Person.h"
@implementation Person
@dynamic age;
@dynamic name;
@end
6.おまじないコード
//
// MyCDataAppDelegate.h
//
#import <UIKit/UIKit.h>
// ここ追加
#import <CoreData/CoreData.h>
@class MyCDataViewController;
@interface MyCDataAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
MyCDataViewController *viewController;
// ここ追加
@private
NSManagedObjectContext *managedObjectContext_;
NSManagedObjectModel *managedObjectModel_;
NSPersistentStoreCoordinator *persistentStoreCoordinator_;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet MyCDataViewController *viewController;
// ここ追加
@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
// ここ追加
- (NSString *)applicationDocumentsDirectory;
@end
//
// MyCDataAppDelegate.m
//
#import "MyCDataAppDelegate.h"
#import "MyCDataViewController.h"
@implementation MyCDataAppDelegate
@synthesize window;
@synthesize viewController;
#pragma mark -
#pragma mark Application lifecycle
/**
これ追加
*/
- (void)awakeFromNib {
viewController.managedObjectContext = self.managedObjectContext;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[window addSubview:viewController.view];
[window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
}
- (void)applicationWillTerminate:(UIApplication *)application {
}
#pragma mark -
#pragma mark Memory management
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
#pragma mark -
#pragma mark Core Data stack
/**
これ追加(ゲッター)
CoreData用に共通のContextを1つここで用意する。
SQLiteファイルへの永続ストアコーディネータ(NSPersistentStoreCoordinator)のインスタンスを、用意したContextにセットする。
*/
- (NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext_ != nil) {
return managedObjectContext_;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext_ = [[NSManagedObjectContext alloc] init];
[managedObjectContext_ setPersistentStoreCoordinator:coordinator];
}
return managedObjectContext_;
}
/**
これ追加(ゲッター)
.xcdatamodeld (.xcdatamodelを内包した)バンドルを指定する。
管理オブジェクトモデル(NSManagedObjectModel)の準備をする。
この管理オブジェクトモデルを使うことで、管理オブジェクト(アプリ側)とレコード(データベース側)とのマッピングさせる。
*/
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel_ != nil) {
return managedObjectModel_;
}
NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"MyCData" ofType:@"momd"];
NSLog(@"データモデルのバンドルディレクトリ(?)のパス %@", modelPath);
NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return managedObjectModel_;
}
/**
これ追加(ゲッター)
永続ストアとしてSQLite(ファイル)を指定する。
この永続ストアコーディネータを使うことで、管理オブジェクトモデル(.xcdatamodel)と永続ストアを関連付けて管理できるようになる。
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSURL *storeURL = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"MyCData.sqlite"]];
NSError *error = nil;
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return persistentStoreCoordinator_;
}
#pragma mark -
#pragma mark Application's Documents directory
/**
これ追加
Returns the path to the application's Documents directory.
*/
- (NSString *)applicationDocumentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}
@end
7.後は普通にコード書く
8.データの読み込みや追加などは、用意したコンテクスト(NSManagedObjectContext)を通じて実行
//
// MyCDataViewController.h
//
#import <UIKit/UIKit.h>
// ここ追加
#import <CoreData/CoreData.h>
@interface MyCDataViewController : UIViewController {
// ここ追加
NSFetchedResultsController *fetchedResultsController_;
NSManagedObjectContext *managedObjectContext_;
// ここ追加
IBOutlet UIButton *addButton;
IBOutlet UIButton *requestButton;
NSMutableArray *persons;
}
// ここ追加
@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
// ここ追加
@property (nonatomic, retain) IBOutlet UIButton *addButton;
@property (nonatomic, retain) IBOutlet UIButton *requestButton;
@property (nonatomic, retain) NSMutableArray *persons;
- (IBAction)addPerson:(id)sender;
- (IBAction)requestPersons:(id)sender;
@end
//
// MyCDataViewController.m
//
#import "MyCDataViewController.h"
// ここ追加
#import "Person.h"
@implementation MyCDataViewController
// ここ追加
@synthesize fetchedResultsController = fetchedResultsController_;
@synthesize managedObjectContext = managedObjectContext_;
@synthesize addButton;
@synthesize requestButton;
@synthesize persons;
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
// ここ追加
self.addButton = nil;
self.requestButton = nil;
}
- (void)dealloc {
// ここ追加
[addButton release];
[requestButton release];
[persons release];
// ここ追加
[fetchedResultsController_ release];
[managedObjectContext_ release];
[super dealloc];
}
/**
これ追加
*/
- (IBAction)addPerson:(id)sender
{
NSLog(@"- (IBAction)addPerson:(id)sender");
NSManagedObjectContext *context = self.managedObjectContext;
Person *person = (Person *)[NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];
[person setAge:[NSNumber numberWithInt:37]];
[person setName:@"Jack"];
NSError *error;
if (![context save:&error]) {
NSLog(@"Error");
}
}
/**
これ追加
*/
- (IBAction)requestPersons:(id)sender
{
NSLog(@"- (IBAction)requestPersons:(id)sender");
NSManagedObjectContext *context = self.managedObjectContext;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Person" inManagedObjectContext:context];
[request setEntity:entity];
// ソート
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];
NSError *error;
NSMutableArray *mutableFetchResults = [[context executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
NSLog(@"no results");
}
[self setPersons:mutableFetchResults];
[mutableFetchResults release];
[request release];
for (Person *person in persons) {
NSLog(@"%@", [person name]);
}
}
@end
後このサンプルでは、InterfaceBuilderでMyCDataViewController.xibにボタン2つ追加してそれぞれIBOutletとIBActionを繋げれば動くはず。
0 件のコメント:
コメントを投稿