Kirill
Kirill

Reputation: 5

Core Data results with @EnvironmentKey

i try to adopt answer from How to re-use the same FetchRequest, rather than the same request in several views?

i build simple app with Core data

//  Count+CoreDataProperties.swift

extension Count {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Count> {
        return NSFetchRequest<Count>(entityName: "Count")
    }

    @NSManaged public var id: UUID?
    @NSManaged public var name: String?
    @NSManaged public var number: Int16

}

    //  CoreDataManager.swift // all structs to fetch core data and set Environment
  
    public struct CountEnvironmentKey: EnvironmentKey {
        public static var defaultValue: [Count] = []
    }
    
    public extension EnvironmentValues {
        var counts: [Count] {
            get { self[CountEnvironmentKey.self] }
            set { self[CountEnvironmentKey.self] = newValue }
        }
    }
    
    public extension View {
        func setCount(_ counts: [Count]) -> some View {
            environment(\.counts,  counts)
        }
    }
    
    struct CountLoaderViewModifier: ViewModifier {
        @FetchRequest( sortDescriptors: [])
        var counts: FetchedResults<Count>
        
        func body(content: Content) -> some View {
            content
                .setCount(Array(counts))
        }
    }
    
    extension View {
        func loadCounts() -> some View {
            modifier(CountLoaderViewModifier())
        }
    }


//  ContentView.swift


struct ContentView: View {
    @Environment(\.managedObjectContext) private var viewContext
    @Environment(\.counts) var counts

    var body: some View {
        NavigationView {
            List {
                ForEach(counts) { item in
                    NavigationLink {
                        Text("\(item.number)")
                    } label: {
                        Text("Item at \(item.name!)")
                    }
                }
                .onDelete(perform: deleteItems)
            }
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    EditButton()
                }
                ToolbarItem {
                    Button(action: addItem) {
                        Label("Add Item", systemImage: "plus")
                    }
                }
            }
            Text("Select an item")
        }

    }

    private func addItem() {
        withAnimation {
            let newItem = Count(context: viewContext)
            newItem.name = "Name"
            newItem.number = 1
            newItem.id = UUID()

            do {
                try viewContext.save()
            } catch {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                let nsError = error as NSError
                fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
            }
        }
    }

    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            offsets.map { counts[$0] }.forEach(viewContext.delete)

            do {
                try viewContext.save()
            } catch {
                let nsError = error as NSError
                fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
            }
        }
    }
}

//  MyEnvApp.swift


@main
struct MyEnvApp: App {
    
    let persistenceController = PersistenceController.shared


    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(\.managedObjectContext, persistenceController.container.viewContext)
               .loadCounts()
        }
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
    }
}

in @main i getting warning Context in environment is not connected to a persistent store coordinator: <NSManagedObjectContext: 0x60000273dfb0> the code from sample @ObservedObject var persistenceManager = PersistenceManager(usage: .main) generate error also, i understand that i need to connect my core data store to environment

thanks for help in advance

Upvotes: 0

Views: 99

Answers (1)

jrturton
jrturton

Reputation: 119242

.loadCounts() is applied as a modifier outside (after) the modifier that sets the managed object context in the environment. This means the environment value is not present in your modifier's body. Try moving .loadCounts() above .environment(\.managedObjectContext, ...).

Upvotes: 2

Related Questions