NB:これは古い質問ですが、それが説明する問題は時代を超えているので、今日質問が投稿されたかのように答えを書きました。
実際、これは複数のデータベースの必要性を示唆するものではありません。だから私たちは持っています:
1)ゲームのシードにのみ使用される事前定義されたデータ(デフォルトデータ)。
データを永続ストア(データベース)にロードするメソッドを記述します。ユーザーデフォルト、defaultDataHasBeenLoadedなどでフラグを設定し、appDelegataで確認します。
2)ユーザーの現在のセーブゲーム。
1対多の関係を持つUsersテーブルとGamesテーブルが必要です。Gamesテーブルで、isCurrentGame属性を追加します。
3)ユーザーがインターネットからシナリオをダウンロードしました。
今では面白くなってきています。そのためのインポート関数またはクラスが必要であり、それをバックグラウンドスレッドで実行する必要があります。そうすれば、新しいシナリオがインポートされている間、ユーザーはプレイを続けたり、スコアなどを確認したりできます。シナリオがインポートされると、ユーザーは通知と新しいシナリオに切り替える機会を受け取る必要があります。
これを行う最も効率的な方法は、iOS 10.0、macOS 10.12、tvOS 10.0、およびwatchOS3.0から利用可能なNSPeristentContainerを使用することです。NSPeristentContainerにデータモデルの名前を付けると、永続ストアが作成またはロードされ、persistentStoreCoördinatorとmanagedObjectContextが設定されます。
// AppDelegate.h or class header file
@property (readonly, strong, nonatomic) NSPersistentContainer *persistentContainer;
@property (readonly, weak, nonatomic) NSManagedObjectContext *managedObjectContext;
// AppDelegate.m or other implementation file
@synthesize persistentContainer = _ persistentContainer;
@synthesize managedObjectContext = _ managedObjectContext;
- (NSPersistentContainer *)persistentContainer
{
@synchronized (self) {
if (_persistentContainer == nil) {
_persistentContainer = [[NSPersistentContainer alloc] initWithName:@"nameOfDataModel"];
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
if (error != nil) {
// Handle the error
} else {
_managedObjectContext = _persistentContainer.viewContext; // NB new name for moc is viewContext!
}
}];
}
}
return _persistentContainer;
}
NSViewControllerのappDelegateからコンテナーを使用するには、viewDidLoadに以下を追加します。
self.representedObject = [(AppDelegate *)[[NSApplication sharedApplication] delegate] persistentContainer];
// Use representedObject in bindings, such as:
[_gameNameTextField bind:NSValueBinding toObject:self
withKeyPath:@"representedObject.game.name"
options:options];
新しいシナリオをインポートするには、performBackgroundTask:を使用します。これは、新しいスレッドと新しいmanagedObjectContext(ここではmoc_backgroundと呼ばれます)を自動的に作成するブロックです。ブロック内で行うことにはすべてmoc_backgroundのみを使用します。ブロック外でメソッドを呼び出す場合は、moc_backgroundを渡します。
NSPersistentContainer *pc = (NSPersistentContainer *)self.representedObject;
pc.viewContext.automaticallyMergesChangesFromParent = YES; // this will ensure the main context will updated automatically
__block id newScenario;
[pc performBackgroundTask:^(NSManagedObjectContext * _Nonnull moc_background) {
NSEntityDescription *scenarioDesc = [NSEntityDescription entityForName:@"Scenario" inManagedObjectContext:moc_background];
NSManagedObject *scenario = [[NSManagedObject alloc] initWithEntity:scenarioDesc insertIntoManagedObjectContext:moc_background];
// configure scenario with the data from newScenario
NSError *error;
BOOL saved = [moc_background save:&error];
// send out a notification to let the rest of the app know whether the import was successfull
}];
問題:ユーザーが「シナリオ」でゲームを保存するとどうなりますか。
これは、誰が最初にそこに到達するか、マージを試みるバックグラウンドスレッド、または保存操作によって異なります。多対1の関係にあるシナリオテーブルをゲームテーブルに追加しても、問題はありません。
問題:すべてのシナリオとすべてのユーザーがコアデータに保存したゲームを追跡するにはどうすればよいですか?
データモデリングには注意が必要です。最初はシンプルに保ち、明確な必要性が見つかったらテーブルとリレーションシップを追加します。そして、テスト、テスト、テスト。