Is it possible to have multiple core data “databases” on one iOS app?

会有一股神秘感。 提交于 2019-11-29 08:56:51

If the data models are the same, you can just setup your MOC so that it uses both persistent stores... one which is read-only and the other that is read/write.

Or, you could use separate MOC for each store.

So, how you want to use it is your only decision factor, since you can have almost any combination of MOC/PSC.

Look at the documentation here for more information.


Edit:

The link given with this question is dead, someone else suggested this link in another deleted answer.

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!