Goal: I want to to show a list of Todo
items by their due dates which I have already achieved. But I also wanna show a list of a different entity, Categories
on the same View above the list of Todo items. The categories are buttons to take you to a list of todo items filtered to that category. I set a relationship of Category to have many todos. How do I change my FetchRequest to support the added relationship?
Here is the current SectionedFetchRequest
below. If I try to add a new FetchRequest for Categories I get a crash.
@SectionedFetchRequest(entity: Todo.entity(),
sectionIdentifier: \.dueDateRelative,
sortDescriptors: [NSSortDescriptor(keyPath: \Todo.dueDate, ascending: true)],
predicate: nil,
animation: Animation.linear)
var sections: SectionedFetchResults<String, Todo>
ForEach(sections) { section in
Section(header: Text(section.id.description)) {
ForEach(section) { todo in
TodoRowView(todo: todo)
.frame(maxWidth: .infinity)
.listRowSeparator(.hidden)
}
.onDelete { indexSet in
deleteTodo(section: Array(section), offsets: indexSet)
}
}
}
// Causes Crash when added to existing Fetch Request
//@FetchRequest(entity: Category.entity(), sortDescriptors: []) var categories: FetchedResults<Category>
You might be overthinking this. If you add a sectionIdentifier
for the category you can offer the option relatively easy.
The variable would look like this
extension Todo{
@objc
var categoryTitle: String{
self.relationship?.title ?? "no category"
}
}
Then add a few variables to the View
//Dictionary to store sort options
let sortOptions: [String: KeyPath<Todo, String>] = ["due date": \Todo.dueDateRelative, "category":\Todo.categoryTitle]
//Variable to use to filter list
@State var selectedSection: String = ""
//filter the `sections` by the selected section
//You can use nsPredicate too
var filteredSections: [SectionedFetchResults<String, Todo>.Element] {
sections.filter({ val in
if !selectedSection.isEmpty {
return val.id == selectedSection
}else{
return true
}
})
}
Then give the user some buttons to select
//Give the user sort options
Menu("sort"){
ForEach(Array(sortOptions.keys).sorted(by: <), id:\.self, content: { key in
Button(key, action: {
sections.sectionIdentifier = sortOptions[key]!
selectedSection = ""
})
})
}
//Give the user section options
Picker("sections", selection: $selectedSection, content: {
ForEach(sections, content: {section in
Text(section.id).tag(section.id)
})
Text("all").tag("")
}).pickerStyle(.segmented)
The ForEach
would display the user selections automatically
ForEach(filteredSections) { section in