在 macOS 中初始化 CoreData

Posted

技术标签:

【中文标题】在 macOS 中初始化 CoreData【英文标题】:Initializing CoreData in macOS 【发布时间】:2018-04-16 18:29:20 【问题描述】:

在 Cocoa 中,Storyboard 的第一个视图控制器将在调用 AppDelegateapplicationDidFinishLaunching 之前调用 viewDidLoad(在第一个视图控制器上)。 由于我在applicationDidFinishLaunching 中获取了我的NSManagedObjectContext,因此我需要等待applicationDidFinishLaunching 才能加载我的数据。

换句话说,在viewDidLoad,我还没有我的NSManagedObjectContext


我现在在做什么:

我在viewDidLoad 中添加了一个applicationDidFinishLaunching 观察者,并在触发时加载数据。

所以(按顺序): 1. ViewController 正在添加一个applicationDidFinishLaunching 观察者。 2. AppDelegates 运行其applicationDidFinishLaunching 并触发观察者。 3. 我可以从我的 ViewController 加载数据。


我意识到我正在中继 viewDidLoad,以便在applicationDidFinishLaunching 之前被调用。如果更改顺序,观察者将添加到applicationDidFinishLaunching 之后,并且不会加载数据。

让我的“CoreDataManager”直接在其init 中从 AppDelegate 获取NSManagedObjectContext 会“更安全”吗?

【问题讨论】:

这里真正的问题是,为什么viewDidLoadapplicationDidFinishLaunching 之前被调用?这不正常。一些奇怪的事情正在发生,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”上调用指定的初始化程序

从 JSON 初始化链接 CoreData 实体

通过UserNotification自定义操作访问时,CoreData无法初始化托管对象

无法在 AppDelegate coredata,Swift 2 中使用(域,代码,userInfo)调用类型“NSError”的初始化程序