WWDC24 SALE: Save 50% on all my Swift books and bundles! >>

SOLVED: Core Data and Lifecycle SwiftUI App

Forums > SwiftUI

Pretty new to SwiftUI and was wondering if anyone knows if Core Data support for the Lycycle Choice of SwiftUI App vs App Kit Delegate is going to be added, or if we can "Simply" copy and past the App Delegate portion that supports Core Data into an app based on SwiftUI App template.

3      

Hi, I would love to know this as well please :) , Many thanks.

3      

Just create your own CoreData class and inject it into your app environment. Below example is for PersistentCloudKitContainer but can easily be changes to just a PersistentContainer.

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

And the custom class

import CoreData
public class PersistentCloudKitContainer {
    // MARK: - Define Constants / Variables
    public static var context: NSManagedObjectContext {
        return persistentContainer.viewContext
    }
    // MARK: - Initializer
    private init() {}
    // MARK: - Core Data stack
    public static var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "Model")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        container.viewContext.automaticallyMergesChangesFromParent = true
        container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        return container
    }()
    // MARK: - Core Data Saving support
    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)")
            }
        }
    }
}

5      

Where are you putting the public class here?

3      

you can put the class wherever you want. i did put it in a separate framework target since i wanted my core data model be shared between ios, macos and tvos.

3      

When following this, i keep getting the error, cannot find type "MyEntity" in scope.

My App.swift and the CoreData.swift files below (created the coredata.swift to hold the public class)

import SwiftUI

@main
struct My_HumidorApp: App {
    let context = PersistentCloudKitContainer.persistentContainer.viewContext
    var body: some Scene {
        WindowGroup {
            ContentView().environment(\.managedObjectContext, context)
        }
    }
}
//
//  CoreData.swift
//  My Humidor
//
//  Created by Adam Hewitt on 28/06/2020.
//

import Foundation
import CoreData
public class PersistentCloudKitContainer {
    // MARK: - Define Constants / Variables
    public static var context: NSManagedObjectContext {
        return persistentContainer.viewContext
    }
    // MARK: - Initializer
    private init() {}
    // MARK: - Core Data stack
    public static var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "My_Humidor")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        container.viewContext.automaticallyMergesChangesFromParent = true
        container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        return container
    }()
    // MARK: - Core Data Saving support
    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)")
            }
        }
    }
}

This is the start of my content view:

    import SwiftUI

struct ContentView: View {
    @Environment(\.managedObjectContext) var moc
    @FetchRequest(entitiy: MyHumidors.entity(), sortDescriptors:[]) var humidor: FetchRequest<MyHumidors>

Any ideas what is causing this from a code perspective?

Edit: I have copied this post over to apple dev also, not sure where it is best placed.

3      

I think the error is in the last part of

@FetchRequest(entitiy: MyHumidors.entity(), sortDescriptors:[]) var humidor: FetchRequest<MyHumidors>

FetchRequest<MyHumidors> should be FetchedResults<MyHumidors>

4      

Is it a bad thing that I want the fetch behavior for Core Data to go through a View Model and the SWIFTUI not to care about the data source or not?

3      

I am new to SwiftUI and since I started using Xcode 12 beta, I was up against the wall trying to use Core Data. I had no problem when I was using Xcode 11 with the AppDelegate and SceneDelegate files. I was actually starting to wrap my head around it.
Basically after a week of multiple attempts at injecting various code snippets including the one posted above, I finally went all in with the Swift App life Cycle and no StoryBoard.

What I discovered was after checking the coreData box on startup, Xcode pre-populated my ContentView() with a whole series of content pertaining to the "timestamp" attribute which it gives by default after it created an Entity named "Item".

That was not the name of my original Entity, but I decided to leave it as "Item" for testing sake.

I decided to delete all the content in the body view and leave what xcode provided in the properties area as seen below. After I left the "timestamp" attribute intact and added my new attributes, I only had to change the keyPath to "Item.name" instead of "Item.timestamp" which xcode originally gave me.

import SwiftUI import CoreData

struct ContentView: View {

@Environment(\.managedObjectContext) private var viewContext

@FetchRequest(entity: Item.entity(),
    sortDescriptors: [NSSortDescriptor(keyPath: \Item.name, ascending: true)],
    animation: .default)

private var items: FetchedResults<Item>

This did the trick and my App is saving perfectly as before. Another thing is that "viewContext" is used more often than what I used to use "managedObjectContext" for, so pay attention to that.

Now, since I'm new to this, I'm hoping this might help someone that might have been struggling with this issue.

4      

Save 50% in my WWDC sale.

SAVE 50% To celebrate WWDC24, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.