【第1回】CoreDataに関して

えっとCoreDataに関して、ちゃんと調べて使おうかなぁと思ったので、
いろいろ調べてみました。
それについて、書こうかと思います。
ちなみにですね...いろいろ試行錯誤で、見てみたらJavaぽくなっちゃてる様な気が....。
それとですね...xcodeのCoreDataのテンプレートがあると思うのですが、使ってないです。
なので、simple applicationのテンプレートでやってます。
今回は、CoreDataを扱えるようにするところまで、書こうかと思います。
まずDataModelから作ります。
あ!それと、CoreDataのフレームワークをプロジェクトに追加しておいて下さい。
まずDataModelから作ります。
[command+N]を押して、テンプレート選択画面がでるので、
CoreDataのところにあるDataModelを選択します。
DataModelのファイルに名前を付けるのですが、[DataModel_V1]とします。
なんでバージョンを付けるかですが、CoreDataは、何らかの変更が発生した場合、
直接変更すると問題が発生するので、バージョン違いでDataModelを用意しないといけません。
複数のバージョン違いのものをマージして読ませてあげたりしないといけないとかいろいろやる必要があります。
そこらへんは、今度、書こうかと思います。
エンティティは、Itemで、ItemIdとnameの属性があるやつを作ります。

20120804234734

できたら、エンティティのItemを選択して、[command+N]を押して、テンプレート選択画面がでるので、
CoreDataのところにある[MSManagedObject subclass]を選択してファイルを作ります。
これで、Item.hとItem.mができると思います。
次に、DataModelを管理するクラスを作ります。
管理するクラス名は、DataModelManagerクラスとします。
まずは、DataModelManager.hの定義です。
DataModelを扱う為には、下記の3つが必要になります。
NSManagedObjectContext
NSManagedObjectModel
NSPersistentStoreCoordinator
それで、3つのオブジェクト内包する形にしたいので、
プロパティとして、定義してあげるのと、そのオブジェクトを生成するメソッドを定義しておきます。

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@interface DataModelManager : NSObject
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
+ (DataModelManager *)dataModelManager;
- (NSManagedObjectContext *)managedObjectContext;
- (NSManagedObjectModel *)managedObjectModel;
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator;
- (NSURL *)applicationDocumentsDirectory;
@end

その実装クラスですが、分解して説明します。
NSManagedObjectModelを生成に関してですが、
このオブジェクトは、DataModelを管理するオブジェクトで、
データモデルの情報(属性とか、関連とか)を保持します。
生成時に、DataModelファイルを読ませてやる必要があります。
実装方法は、下の様な感じになります。

NSURL *modelURL =
  [[NSBundle mainBundle] URLForResource:@"<DataModel名>" withExtension:@"momd"];
[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

次に、NSPersistentStoreCoordinatorの生成です。
このオブジェクトは、永続ストア管理を行うオブジェクトです。
永続ストアとコンテキスト間の仲介を行ったりしています。

NSURL *storeURL =
   [[self applicationDocumentsDirectory]
              URLByAppendingPathComponent:@"<Store名>"];
[[NSPersistentStoreCoordinator alloc] 
           initWithManagedObjectModel:_managedObjectModel];

最後に、NSManagedObjectContextの生成です。
このオブジェクトは、モデルのオブジェクト管理を行うオブジェクトで、
設定とかスコープとかいろいろ管理しています。
通常は、1つストアに1つのコンテキストオブジェクトが存在します。
複数のストアの場合もあるらしいのですが、やったことないので、詳しくは、わかりません。

_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:_persistentStoreCoordinator];

全体の実装です。

#import "DataModelManager.h"

@implementation DataModelManager
static DataModelManager *_manager;
@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
+ (DataModelManager *)dataModelManager
{
  if (!_manager) {
      _manager = [[DataModelManager alloc]init];
  }
  return _manager;
}
- (NSManagedObjectContext *)managedObjectContext
{
  if (_managedObjectContext) {
     return _managedObjectContext;
  }
  _managedObjectModel = [self managedObjectModel];
  _persistentStoreCoordinator = [self persistentStoreCoordinator];
  _managedObjectContext = [[NSManagedObjectContext alloc] init];
  [_managedObjectContext setPersistentStoreCoordinator:_persistentStoreCoordinator];
  return _managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel
{
  NSURL *modelURL = 
    [[NSBundle mainBundle] URLForResource:@"DataModel_V1" withExtension:@"momd"];
  return [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
  if (_persistentStoreCoordinator != nil) {
     return _persistentStoreCoordinator;
  }
  NSURL *storeURL =
     [[self applicationDocumentsDirectory]
              URLByAppendingPathComponent:@"datamodel.sqlite"];
    NSError *error = nil;
    _persistentStoreCoordinator = 
       [[NSPersistentStoreCoordinator alloc] 
           initWithManagedObjectModel:_managedObjectModel];
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType 
          configuration:nil URL:storeURL options:nil error:&error]) {
        NSLog(@"persistentStore error %@, %@", error, [error userInfo]);
        abort();
    }    
    return _persistentStoreCoordinator;
}
- (NSURL *)applicationDocumentsDirectory
{
    return [[[NSFileManager defaultManager] 
              URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
@end

それで、どっからもアクセス可能なクラスとしたいので、下記のメソッドも定義しています。

+ (DataModelManager *)dataModelManager
{
  if (!_manager) {
      _manager = [[DataModelManager alloc]init];
  }
  return _manager;
}

これで、CoreDataを扱う準備は、完了です。
この続きは、次回とします。