Initializing CoreData in macOS

跟風遠走 提交于 2021-02-10 19:54:30

问题


In Cocoa, Storyboard's first view controller will call viewDidLoad (on the first view controller) before AppDelegate's applicationDidFinishLaunching is called.
Since I am grabbing my NSManagedObjectContext in applicationDidFinishLaunching, I need to wait for applicationDidFinishLaunching before loading my data.

In other words, in viewDidLoad, I don't yet have my NSManagedObjectContext.


What I'm doing now:

I'm adding an applicationDidFinishLaunching observer in my viewDidLoad, and load the data when that is triggered.

So (in order):
1. ViewController is adding an applicationDidFinishLaunching observer.
2. AppDelegates runs its applicationDidFinishLaunching and triggering the observer.
3. I can load the data from my ViewController.


I realized I'm relaying on viewDidLoad to be called before applicationDidFinishLaunching. If that order is changed, the observer will be added after applicationDidFinishLaunching and data will not load.

Would it be 'safer' to let my 'CoreDataManager' get the NSManagedObjectContext from AppDelegate directly in its init?


回答1:


May I suggest a revised design instead, remove any use of core data from the AppDelegate class and move any initialisation into your root view controller instead and then use dependency injection to pass your managed object context to other view controllers (or have a separate core data manager class implemented as a singleton). This will free you from issues like this.




回答2:


The answer provided by Joakim Danielson here is what I ended up doing (credit where credit is due).

--EDIT

Ended up doing exactly what Joakim Danielson suggested. The given code to get the context, may be in the AppDelegate by default, but it's completely independent. It can be moves anywhere really.
I basically moved the following func into my CoreDataManager class and I'm calling it in the 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
}()

Also, not to forget that the saveContext() in AppDelegate needs to be updated (by default it points to its own getter).


(Previous answer:)

I've changed (somewhat) the signature lazy var persistentContainer: NSPersistentContainer provided in the AppDelegate (by checking CoreData when creating a project) to: 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
}()

My CoreDataManager (which is a singleton), can now use this init:

class CoreDataManager {

static let shared = CoreDataManager()

weak var context: NSManagedObjectContext!

init() {
    self.context = AppDelegate.coreDataContext
}

Using this pattern (in AppDelegate):

static var coreDataContext: NSManagedObjectContext = {...}()

Ensures that the block will be executed only once.

Now, it is safe to use the NSManagedObjectContext at any stage.



来源:https://stackoverflow.com/questions/49864000/initializing-coredata-in-macos

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