I am trying to make dynamic filters of Core Data items with SwiftUI. Core Data Entity: Item. Attributes: date (Date), done (Boolean), name (String).
Provided code creates 3 instances of Item entity. Above the list there is a segmented control to change filter value. All turns off filter (doneFilter is set to nil). Not finished turns on filter (sets doneFilter to false).
There is also an init that sets fetchRequest based on segmented control.
PROBLEM
Build fails with error:
Variable 'self.fetchRequest' used before being initialized
What is wrong with my code?
ContentView.swift
import SwiftUI
struct ContentView: View {
@Environment(\.managedObjectContext) var moc
var body: some View {
NavigationView {
VStack {
ListView()
}
.navigationBarTitle("Items")
.navigationBarItems(
leading:
Button(action: {
for number in 1...3 {
let item = Item(context: self.moc)
item.date = Date()
item.name = "Item \(number)"
item.done = false
do {
try self.moc.save()
}catch{
print(error)
}
}
}) {
Text("Add 3 items")
}
)
}
}
}
ListView.swift
import SwiftUI
struct ListView: View {
@Environment(\.managedObjectContext) var moc
var fetchRequest: FetchRequest<Item>
var items: FetchedResults<Item> { fetchRequest.wrappedValue }
@State var doneFilter :Bool? = nil
var doneStatus: Binding<Int> { Binding<Int>(
get: {
if self.doneFilter == false {
return 1
} else {
return 0
}
},
set: {
switch $0 {
case 1:
self.doneFilter = false
default:
self.doneFilter = nil
}
})
}
var body: some View {
List {
Picker(selection: doneStatus, label: Text("Picker")) {
Text("All").tag(0)
Text("Not finished").tag(1)
}
.pickerStyle(SegmentedPickerStyle())
.padding()
ForEach(items, id: \.self) {item in
HStack {
Text("\(item.name ?? "default item name")")
Spacer()
Toggle(isOn: Binding<Bool>(
get: { item.done },
set: {
item.done = $0
try? self.moc.save()
})) {
Text("Done")
}
.labelsHidden()
}
}
.onDelete(perform: removeItem)
}
}
func removeItem(at offsets: IndexSet) {
for offset in offsets {
let item = items[offset]
moc.delete(item)
}
try? moc.save()
}
init() {
if let filter = doneFilter {
fetchRequest = FetchRequest<Item>(entity: Item.entity(), sortDescriptors: [
NSSortDescriptor(keyPath: \Item.name, ascending: true)
], predicate: NSPredicate(format: "done = %d", filter))
} else {
fetchRequest = FetchRequest<Item>(entity: Item.entity(), sortDescriptors: [
NSSortDescriptor(keyPath: \Item.name, ascending: true)
])
}
}
}