プログラミング言語の復習などは、文法などから入るのが自然なのだろうが、少々ダルいので、JakartaEE の時と同様、データベース – ORM に手をつける。
Objective-C (Swift でもそうだが)の ORM といえば、coreData なのだが、ここでも GUI は使わずにコマンドラインから扱う。(GUI での使用例はこちら)
なお、「なんで、GUI を使わないで、コマンドラインのサンプルで済ませるんですか?」とリアルでも訊かれることがあるが、たぶん、育った環境w
それに加えて swift を勉強していた時に、コマンドラインのサンプルのみからなる教科書を使ったんだが、これがけっこう効果的だったから、という個人的な体験。
サンプルコード
それで、いきなりだが、完成されたコードを示す。
少々、古い書き方だが、動くことは動く。
NSPersistenceContainer を使いたい方は頑張って書き直してください。
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "Person+CoreDataClass.h"
/*
以下の定義は不要だが、念のため.
というか、あると Person が二つあることになるのでエラー出ます。
@interface Person : NSObject {
NSString *name;
}
@property(nonatomic)NSString *name;
@end
// Person クラスの実装
@implementation Person : NSObject
@synthesize name;
@end
*/
int main(int argc, const char * argv[]) {
NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"Model"ofType:@"momd"];
NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
NSManagedObjectModel *managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
NSArray* paths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
NSString* dir = [paths objectAtIndex:0];
NSString* dbPath = [dir stringByAppendingPathComponent:@"sqlite.db"];
NSURL *url = [NSURL fileURLWithPath:dbPath];
NSError *error = nil;
NSPersistentStoreCoordinator* coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:managedObjectModel];
if (![coordinator
addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:url
options:nil
error:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
NSManagedObjectContext *managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[managedObjectContext setPersistentStoreCoordinator:coordinator];
Person *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person"
inManagedObjectContext:managedObjectContext];
person.name = @"akiba";
NSError* error2 =nil;
[managedObjectContext save:&error2];
return 0;
}
何としてもワンファイルで済ませたかったが、流石に coreData だとそうもいかない。
多分、ネットを彷徨してこの記事に辿り着いた人ならわかると思うが、coreData を使う場合は、「モデルからコードを生成する」という操作がどうしても必要だから。
なお、後述する Xcode 上での操作を完了させ、ビルドすると「書類」フォルダ直下に以下のようなデータベースが作成される。

しっかり永続化されてますね。
3レコードあるのは、3回ランさせたからw
なお、カラムはすべて Z から始まってますが、この接頭子が付く理由は誰もわかってません。
このソースコードの解説もしたいところなのだが、まずは動かすための手順を説明していく。
Xcode 上での操作
基本的に
モデルの作成→コードの生成
と進む。
モデルの作成
プロジェクト作成時に use coreData にチェックを入れておけば、モデルを記述するファイルは自動でできるのだが、コマンドラインを選んだ場合は、このオプションは選べないので、自分で追加する。
適当なグループでファイルを追加。

上の画面で coreData -> Data Model を選ぶ。
すると選んだグループなどに Model.xcdatamodeled が追加されるので、次はこれを編集。

Entity がテーブル、attribute がカラムになるので、これを意識して .xcmodeled ファイルを編集。
最初はテーブル一つ、カラム一つから始めるといいと思う。
もちろん、複数のテーブルを作成、カラム同士を One To や Many To などで結びつけるという ORM らしい使い方もできるのだが、ここでやってしまうと混乱するだけなのでここではスキップ。
なお、以前の Xcode には、関係性(relationship)をグラフィカルに表示する機能もあったのだが、現在では無くなっているようだ。
コードの生成
モデルが定義できたので、次はモデルを使ってコードを生成する。
menu -> editor -> Create NSManagedObject Subclasses…
を選ぶ。
なお、この時、画面右の生成する言語で swift か obj-c かを指定する。

デフォだと swift が指定されているので、obj-c の時はもちろん Objective-C で。
すると一つの entity に対し4ファイルが生成される。
Person という entity があった場合は
Person+coreDataClass.h
Person+coreDataClass.m
Person+coreDataProperties.h
Person+coreDataProperties.h
の4つ。
+がなんとも特徴的。
このファイルの生成も3通りのやり方がある(Xcode14 では、一つしかないです)のだが、エンティティ一つ程度であれば、深く検討する必要はないでしょう。とりあえず生成して、ビルド時に微調整でいいと思います。
ビルド
操作的には以上で完了です。
単純に save しているだけなので、一回走らせるたびに、sqlite.db に name = “akiba” のレコードが追加されていきます。
その他
初学者がまず気にしておく点は、永続化すべきクラスは NSObject を継承しているのではなく、NSManagedObject を継承している点。
だから、インスタンスを生成するときも
Person *person = [[Person alooc] init];
とするのではなく
Person *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person"
inManagedObjectContext:managedObjectContext];
とします。
また、通常のオブジェクトとは違っているので、データベース操作時には
NSManagedObjectContext
や
NSPersistentStoreCoordinator
の実体(オブジェクト)が必要という理屈です。
ところで、「coreData objective-c」あたりで検索をかけるとこんな記事がかなり上位にヒットしますが、初学者でこの記事読んで coreData を実際に使えるようになるかというと難しいんではないでしょうか。
記事自体が悪いということではなくて、それだけ情報が少ないってことです。
Xcode14 だとエラーが出ます
Xcode14 上で上記の手順でビルドしてもエラーが出るようです。
Multiple commands produce...
という。
はて?
上の場合は、main.m 以外をコンパイル対象から取り除けば、エラーは消えるんですが、なんか気持ち悪いですね。
発展
今回は、「とりあえず CoreData を使う」ということに主眼を置いたが、使い込むとなると、例えば、検索条件をもっと詳細に設定したいという要求が出てくると思う。
NSPredicate
検索設定に使う。
『CoreData を用いてデータ管理を行う』初学者向け
『NSPredicate 全構文解説』マニアック
などなど。


