在 macOS 中初始化 CoreData
Posted
技术标签:
【中文标题】在 macOS 中初始化 CoreData【英文标题】:Initializing CoreData in macOS 【发布时间】:2018-04-16 18:29:20 【问题描述】:在 Cocoa 中,Storyboard 的第一个视图控制器将在调用 AppDelegate
的 applicationDidFinishLaunching
之前调用 viewDidLoad
(在第一个视图控制器上)。
由于我在applicationDidFinishLaunching
中获取了我的NSManagedObjectContext
,因此我需要等待applicationDidFinishLaunching
才能加载我的数据。
换句话说,在viewDidLoad
,我还没有我的NSManagedObjectContext
。
我现在在做什么:
我在viewDidLoad
中添加了一个applicationDidFinishLaunching
观察者,并在触发时加载数据。
所以(按顺序):
1. ViewController 正在添加一个applicationDidFinishLaunching
观察者。
2. AppDelegates 运行其applicationDidFinishLaunching
并触发观察者。
3. 我可以从我的 ViewController 加载数据。
我意识到我正在中继 viewDidLoad
,以便在applicationDidFinishLaunching
之前被调用。如果更改顺序,观察者将添加到applicationDidFinishLaunching
之后,并且不会加载数据。
让我的“CoreDataManager”直接在其init
中从 AppDelegate 获取NSManagedObjectContext
会“更安全”吗?
【问题讨论】:
这里真正的问题是,为什么viewDidLoad
在applicationDidFinishLaunching
之前被调用?这不正常。一些奇怪的事情正在发生,Core Data 只是症状,而不是原因。
@TomHarrington 恐怕是在可可的土地上:***.com/questions/36681587/…
抱歉,我在考虑 ios。没关系。
@TomHarrington 你说得对。这真的很违反直觉,在 Apple 的示例中,它们指示 NSManagedObjectContext
指针在 applicationDidFinishLaunching
中向右传递。
【参考方案1】:
我是否可以建议修改设计,从 AppDelegate 类中删除对核心数据的任何使用,并将任何初始化移动到您的根视图控制器中,然后使用依赖注入将您的托管对象上下文传递给其他视图控制器(或单独的核心数据管理器类实现为单例)。这将使您摆脱此类问题。
【讨论】:
我花了一些时间才意识到这确实是最好的方法。我基本上只是添加了一些解释和代码,但是是的,CoreData 代码可以很容易地移动,它是一个独立的函数。【参考方案2】:Joakim Danielson 在这里提供的答案是我最终所做的(信用到期)。
--编辑
最终完全按照 Joakim Danielson 的建议行事。获取上下文的给定代码,默认情况下可能在AppDelegate
中,但它是完全独立的。它真的可以在任何地方移动。
我基本上将以下函数移动到我的CoreDataManager
类中,我在init()
中调用它:
lazy var persistentContainer: NSPersistentContainer =
let container = NSPersistentContainer(name: "AppName")
container.loadPersistentStores(completionHandler: (storeDescription, error) in
if let error = error
// Replace this implementation with code to handle the error appropriately.
fatalError("Unresolved error \(error)")
)
return container
()
另外,不要忘记AppDelegate
中的saveContext()
需要更新(默认情况下它指向自己的getter)。
(上一个答案:)
我已将AppDelegate
中提供的签名lazy var persistentContainer: NSPersistentContainer
(通过在创建项目时检查CoreData
)更改(某种程度上)为:static var persistentContainer: NSPersistentContainer
。
static var coreDataContext: NSManagedObjectContext =
let container = NSPersistentContainer(name: "AppName")
container.loadPersistentStores(completionHandler: (storeDescription, error) in
if let error = error
// Replace this implementation with code to handle the error appropriately.
fatalError("Unresolved error \(error)")
)
return container.viewContext
()
我的CoreDataManager
(这是一个单例),现在可以使用这个初始化:
class CoreDataManager
static let shared = CoreDataManager()
weak var context: NSManagedObjectContext!
init()
self.context = AppDelegate.coreDataContext
使用这种模式(AppDelegate
):
static var coreDataContext: NSManagedObjectContext = ...()
确保块只执行一次。
现在,在任何阶段使用NSManagedObjectContext
都是安全的。
【讨论】:
以上是关于在 macOS 中初始化 CoreData的主要内容,如果未能解决你的问题,请参考以下文章
CoreData:错误:无法在 NSManagedObject 类上调用指定的初始化程序
CoreData:错误:无法在 NSManagedObject 类“Collect”上调用指定的初始化程序
CoreData:错误:无法在 NSManagedObject 类“BNRItem”上调用指定的初始化程序
通过UserNotification自定义操作访问时,CoreData无法初始化托管对象
无法在 AppDelegate coredata,Swift 2 中使用(域,代码,userInfo)调用类型“NSError”的初始化程序