What is the best way to incorporate Core Data into the new App Structure?
For example, I have waged to get it working using the following, but is this the best way to do this?
Code Block import SwiftUI import CoreData @main struct SessionsApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var body: some Scene { WindowGroup { let context = appDelegate.persistentContainer.viewContext ContentView() .environment(\.managedObjectContext, context) } } }
Then In AppDelegate the code is like this
Code Block import UIKit import CoreData class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { print("UIApplication, didFinishLaunchingWithOptions") return true } // MARK: - Core Data stack lazy var persistentContainer: NSPersistentContainer = { let container = NSPersistentContainer(name: "Sessions") container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } }) return container }() // MARK: - Core Data Saving support 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)") } } } }
Finally
and lastly it is used in this View, which fails to dynamically preview but still works...Code Block import SwiftUI import CoreData struct ContentView: View { @Environment(\.managedObjectContext) private var context @FetchRequest(entity: Session.entity(), sortDescriptors: []) private var sessions: FetchedResults<Session> @State private var showingAddScreen:Bool = false var body: some View { NavigationView { List { ForEach(sessions, id:\.id) {session in Text("\(session.name ?? "unknown")") } } .navigationTitle("Sessions") .navigationBarItems(trailing: Button("Add", action: { self.showingAddScreen.toggle() })) } .sheet(isPresented: $showingAddScreen, onDismiss: {self.showingAddScreen.toggle()}) { SessionFormView() } } } struct ContentView_Previews: PreviewProvider { static let coreDataHelper = CoreDataHelper() static let context = coreDataHelper.persistentContainer.viewContext static var previews: some View { ContentView().environment(\.managedObjectContext, context) } }
Advice ?
Please let me know if there is a much better way...cheers
don
Hi Don, you don't need to create a separate class that conforms to UIApplicationDelegate. Set up your Core Data stack in a separate struct (e.g. "CoreDataStack") and expose viewContext as a static variable. You can then inject it into your content view.
Code Block swift struct CoreDataStack { static var viewContext: NSManagedObjectContext { return persistentContainer.viewContext } static var persistentContainer: NSPersistentContainer = { let container = NSPersistentContainer(name: "Sessions") container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } }) return container }() static func saveContext () {...} }
Code Block swift @main struct SessionsApp: App { var body: some Scene { WindowGroup { ContentView() .environment(\.managedObjectContext, CoreDataStack.viewContext) } } }