注意:这是一个老问题,但它描述的问题是永恒的,所以我写了答案,就好像问题是今天发布的一样。
实际上,这并不意味着需要多个数据库。所以我们有:
1) 仅用于播种游戏的预定义数据(默认数据)。
编写一个将数据加载到持久存储(数据库)中的方法。在用户默认、defaultDataHasBeenLoaded 或类似的东西中设置一个标志,并在 appDelegata 中检查它。
2) 用户当前保存的游戏。
您需要具有一对多关系的 Users 表和 Games 表。在 Games 表中添加 isCurrentGame 属性。
3) 用户从互联网上下载了一个场景。
现在它变得有趣了。您将需要一个导入函数或类,并且您需要在后台线程上运行它。这样,您的用户可以在导入新场景的同时继续玩游戏,或者查看他们的分数或其他内容。导入场景后,用户应该会收到通知并有机会切换到新场景。
最有效的方法是使用 NSPeristentContainer,它在 iOS 10.0、macOS 10.12、tvOS 10.0 和 watchOS 3.0 中可用。为 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
}];
问题:当用户在“场景”中保存游戏时会发生什么。
这取决于谁先到达那里,尝试合并的后台线程或保存操作。如果将具有多对一关系的 Scenario 表添加到 Game 表中,应该不会有任何问题。
问题:如何在核心数据中跟踪所有场景和所有用户保存的游戏?
数据建模可能很棘手。一开始保持简单,当您发现明确需要时添加表格和关系。然后测试,测试,测试。