Creating NSPresistantContainer in Appdelegate / scene builder

With the recent changes to allow for an app to be completely in SwiftUI, I am trying to re-create a simple core data and SwiftUI app.

How can a NSPresistantContainer be setup with the new app delegate adaptor and scene builder? I have attempted what has worked previously by creating a lazy var in the app delegate and then providing that as an adaptor on the app struct.


What is the correct way to setup the NSPresistantContainer so the NSManagedObjectModel is loaded?

Code Block swift
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if isDataSet() == false {
setDefaultData()
}
return true
}
lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "breakapp")
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()
func saveContext () {
    let context = persistentContainer.viewContext
    if context.hasChanges {
        do {
            try context.save()
        } catch {
            let nserror = error as NSError
            fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
        }
    }
}
func setDefaultData() {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
for (i, weekday) in Constants.CoreData.weekdays.enumerated() {
let user = NSManagedObject(entity: Weekday.entity(), insertInto: managedContext)
user.setValue("\(weekday)", forKey: Constants.CoreData.Attributes.label)
user.setValue(i, forKey: Constants.CoreData.Attributes.sortNumber)
}
try? managedContext.save()
}
func isDataSet() -> Bool {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return true }
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: Constants.CoreData.Entities.weekday)
let result = try? managedContext.fetch(fetchRequest)
return result?.count != 0
}
}
@main
struct TakeABreakApp: App {
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
@Environment(\.scenePhase) private var scenePhase
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
struct TakeABreakApp_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}


Answered by alexanderboswell in 622821022
Solved it with this:

Code Block swift
import CoreData
public class MyPersistentContainer {
public static var context: NSManagedObjectContext {
return persistentContainer.viewContext
}
private init() {
}
public static var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "breakapp")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
public static func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}


and
Code Block swift
import SwiftUI
import CoreData
@main
struct TestApp: App {
let context = MyPersistentContainer.persistentContainer.viewContext
var body: some Scene {
WindowGroup {
ContentView().environment(\.managedObjectContext, context)
}
}
}



Accepted Answer
Solved it with this:

Code Block swift
import CoreData
public class MyPersistentContainer {
public static var context: NSManagedObjectContext {
return persistentContainer.viewContext
}
private init() {
}
public static var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "breakapp")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
public static func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}


and
Code Block swift
import SwiftUI
import CoreData
@main
struct TestApp: App {
let context = MyPersistentContainer.persistentContainer.viewContext
var body: some Scene {
WindowGroup {
ContentView().environment(\.managedObjectContext, context)
}
}
}



In the App struct you can access the persistent container to set the viewContext on the Environment like this:

Code Block
import SwiftUI
import CoreData
@main
struct MasterDetailApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView().environment(\.managedObjectContext, appDelegate.persistentContainer.viewContext)
}
}
}

Creating NSPresistantContainer in Appdelegate / scene builder
 
 
Q