Reputation: 5
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
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