NB: This is an old question, but the problems it describes are timeless, so I've written the answer as if the question were posted today.
Actually, none of this suggests the need for multiple databases. So we have:
1) Pre-defined data (Default data) that is only used for seeding the
game.
Write a method that loads the data into the persistent store (database). Set a flag in user default, defaultDataHasBeenLoaded or something like that, and check that in the appDelegata.
2) The user's current save game.
You need a Users table and a Games table with a one-to-many relationship. In the Games table you add an isCurrentGame attribute.
3) The user has downloaded a scenario from the Internet.
Now it's getting interesting. You will need an import function or class for that and you'll want to run that on a background thread. That way, your user can continue playing, or looking looking at their scores or whatever, while the new scenario is being imported. When the scenario has been imported, the user should get a notification and the opportunity to switch to the new scenario.
The most efficiënt way to do this is to use NSPeristentContainer which is available from iOS 10.0, macOS 10.12, tvOS 10.0 and watchOS 3.0. Give NSPeristentContainer the name of the data model and it will create or load a persistent store and set the persistentStoreCoördinator and the 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;
}
To use the the container from the appDelegate in an NSViewController, you add the following to 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];
To import the new scenario, use performBackgroundTask:, a block which will automatically create a new thread and a new managedObjectContext (here called moc_background). Use only moc_background for anything you do in the block -- if you call a method outside the block, pass it 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
}];
Problem: What happens when the user saves the game whilst on a
"scenario".
That depends on who gets there first, the background thread that attempts to merge or the save operation. If you add a Scenario table with many-to-one relationship to the Game table, there should not be any problems.
Problem: How do I keep track of all the scenarios and all the user
saved games in core data?
Data modeling can be tricky. Keep it simple at first and add tables and relationships when you find a clear need for them. And then test, test, test.