Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 使用AppDelegate作为单例定义核心数据的上下文_Ios_Swift_Core Data_Nsmanagedobjectcontext - Fatal编程技术网

Ios 使用AppDelegate作为单例定义核心数据的上下文

Ios 使用AppDelegate作为单例定义核心数据的上下文,ios,swift,core-data,nsmanagedobjectcontext,Ios,Swift,Core Data,Nsmanagedobjectcontext,我试图了解核心数据的NSManagedObjectContext。如果在创建新项目时选中了“核心数据”复选框,那么Xcode 10.1将提供大量的样板文件。但我发现如何为每个视图控制器设置当前上下文有点令人困惑。我想我有一个更好的方法,我正在寻找建议来确认,或者让我回到正确的轨道上 例如,在样板AppDelegate代码中,didFinishLaunchingWithOptions为MasterViewController提供如下上下文: let masterNavigationControll

我试图了解核心数据的NSManagedObjectContext。如果在创建新项目时选中了“核心数据”复选框,那么Xcode 10.1将提供大量的样板文件。但我发现如何为每个视图控制器设置当前上下文有点令人困惑。我想我有一个更好的方法,我正在寻找建议来确认,或者让我回到正确的轨道上

例如,在样板AppDelegate代码中,didFinishLaunchingWithOptions为MasterViewController提供如下上下文:

let masterNavigationController = splitViewController.viewControllers[0] as! UINavigationController
let controller = masterNavigationController.topViewController as! MasterViewController
controller.managedObjectContext = self.persistentContainer.viewContex
let context = AppDelegate.shared.persistentContainer.viewContext
AppDelegate.shared.saveContext()
在MasterViewController中,上下文的第一次使用是从fetchedResultsController获取的,并且提供了保存上下文的代码,即使AppDelegate已经有一个saveContext()函数可用于执行相同的操作:

@objc
func insertNewObject(_ sender: Any) {
    let context = self.fetchedResultsController.managedObjectContext
    let newEvent = Event(context: context)

    // If appropriate, configure the new managed object.
    newEvent.timestamp = Date()

    // Save the context.
    do {
        try context.save()
    } catch {
        // Replace this implementation with code to handle the error appropriately.
        // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        let nserror = error as NSError
        fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
    }
}
在我使用多个视图控制器的应用程序中,我在尝试重新声明或移交每个需要的上下文时都犯了错误,因此我不得不应对由于无意中有多个上下文四处飞行而导致的错误

所以我的问题是:我是否犯了一个错误,或者以下方法是否有缺点:

1) 将AppDelegate设置为单例:

class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate {

var window: UIWindow?

static let shared = AppDelegate()
…
2) 在每个需要的类中,总是这样定义上下文(我假设我只需要一个):

let masterNavigationController = splitViewController.viewControllers[0] as! UINavigationController
let controller = masterNavigationController.topViewController as! MasterViewController
controller.managedObjectContext = self.persistentContainer.viewContex
let context = AppDelegate.shared.persistentContainer.viewContext
AppDelegate.shared.saveContext()
3) 每当需要保存上下文时,按如下方式执行:

let masterNavigationController = splitViewController.viewControllers[0] as! UINavigationController
let controller = masterNavigationController.topViewController as! MasterViewController
controller.managedObjectContext = self.persistentContainer.viewContex
let context = AppDelegate.shared.persistentContainer.viewContext
AppDelegate.shared.saveContext()

这看起来更简单、更清晰、更不容易出错,而且在我的实现中似乎很有效。有没有我没有看到的问题

老实说,苹果示例/模板对于初学者来说总是一个糟糕的例子,因为它们只显示一件事,而在rest上“hack”(例如强制展开所有内容)。初学者往往只是照搬这种方法

免责声明:我指的是中大型应用程序。在小型应用程序中,您总是可以打破这些规则和建议,因为不使用它们会更容易,并导致更简单的应用程序

将AppDelegate设置为单例: 在99%的情况下,您不应自行实例化
AppDelegate
。它通过
UIApplication
/
@UIApplicationMain
注释为您处理

AppDelegate
已经是单例的,因为每个应用程序在整个生命周期中只有一个委托。您可以通过
UIApplication.shared.delegate作为访问它?AppDelegate

但您不应该这样做。
AppDelegate
通过为系统和您的代码之间的通信提供入口点,在每个应用程序中扮演特定角色,并且您不应该向其添加其他角色(如句柄数据库)。在代码库的某个地方访问它,大多数情况下都是代码气味和糟糕架构的迹象

分离岩心数据栈 数据库访问是良好使用单例模式的少数几个例子之一。但是,您不应该使用
AppDelegate
,而应该创建单独的服务,该服务只负责处理与coredata的通信(例如创建和处理堆栈、发送查询等)

所以,
CoreDataService
是一条路要走

访问核心数据 使用Singleton并不意味着您可以通过键入
Singleton.shared
在任何地方访问它。这将大大降低组件的可测试性,并使它们与单例高度耦合

相反,你应该阅读并注入你的单身。例如:

类MyViewController:UIViewController{
让dataBaseManager:CoreDataService
init(使用dataBaseManager:CoreDataService){
self.dataBaseManager=数据库管理器
super.init(nibName:nil,bundle:nil)
}
}
理想情况下,您应该更进一步,只向控制器提供它真正需要的:

协议事件提供程序{
func getEvents(带回调:[Event]->Void)
}
扩展CoreDataService:EventsProvider{
func getEvents(带回调:[Event]->Void){
//您的核心数据查询在这里
}
}
类MyViewController:UIViewController{
让eventsProvider:eventsProvider
init(带有eventsProvider:eventsProvider){
self.eventsProvider=eventsProvider
super.init(nibName:nil,bundle:nil)
}
}
让vc=MyViewController(使用:CoreDataService.shared)
多重语境 拥有多个
NSManagedObjectContext
可能会很方便并提高性能,但前提是您知道如何使用它们。
这是一个更高级的主题,所以您现在可以忽略它。

您可以在

中了解它。一个有趣的实验是使用响应器链,将insertNewObject方法移动到应用程序委托,并将其更改为调用[self-saveContext]。然后让add按钮将操作发送到nil而不是self。或者在情节提要中,拖动一个条形按钮项,并将其从动作拖动到第一响应者图标(它位于视图控制器的顶部,也在左侧栏中),然后选择insertNewObject并进行尝试

2)这个选项很有意义,非常简单,而且效果很好。@tkhelm,这一定是正确的答案。