How can I create a predicate so that when the user selects "Full Body" it returns the entire list with no predicate? Right now, it is returning "part" which corresponds to the muscle groups I have set (Abs, Legs, Push, Pull). I want to return all of the options when "Full Body" is selected. How could I write an If statement so that the predicate is not used?
import SwiftUI
var parts = ["Abs", "Legs", "Push", "Pull", "Full Body"]
struct ExerciseList: View {
@State private var selectedPart = " "
var body: some View {
NavigationView {
VStack (alignment: .leading) {
NavigationLink(destination: AddExerciseView()){
Text("Add Exercise")
.fontWeight(.bold)
}
Picker("Body Part", selection: $selectedPart) {
ForEach(parts, id:\.self) { part in
Text(part)
}
}.pickerStyle(.segmented)
ListView(part:selectedPart)
}
}
}
}
import SwiftUI
struct ListView: View {
var part: String
@FetchRequest var exercises: FetchedResults<Exercise>
init(part: String) {
self.part = part
self._exercises = FetchRequest(
entity: Exercise.entity(),
sortDescriptors: [],
predicate: NSPredicate(format: "musclegroup == %@", part as any CVarArg)
)
}
var body: some View {
List(exercises) { e in
Text(e.exercisename)
}
}
}
CodePudding user response:
you could try this simple approach in ListView
:
init(part: String) {
self.part = part
self._exercises = FetchRequest(
entity: Exercise.entity(),
sortDescriptors: [],
predicate: (part == "Full Body")
? nil
: NSPredicate(format: "musclegroup == %@", part as any CVarArg)
)
}
CodePudding user response:
It's not a good idea to init objects inside View structs because the heap allocation slows things down. You could either have all the predicates created before hand or create one when the picker value changes, e.g. something like this:
// all the Picker samples in the docs tend to use enums.
enum Part: String, Identifiable, CaseIterable {
case abs
case legs
case push
case pull
case fullBody
var id: Self { self }
// Apple sometimes does it like this
// var localizedName: LocalizedStringKey {
// switch self {
// case .abs: return "Abs"
// case .legs: return "Legs"
// case .push: return "Push"
// case .pull: return "Pull"
// case .fullBody: return "Full Body"
// }
// }
}
struct ExerciseListConfig {
var selectedPart: Part = .fullBody {
didSet {
if selectedPart == .fullBody {
predicate = nil
}
else {
// note this will use the lower case string
predicate = NSPredicate(format: "musclegroup == %@", selectedPart.rawValue)
}
}
}
var predicate: NSPredicate?
}
struct ExerciseList: View {
@State private var config = ExerciseListConfig()
var body: some View {
NavigationView {
VStack (alignment: .leading) {
Picker("Body Part", selection: $config.selectedPart) {
//ForEach(Part.allCases) // Apple sometimes does this but means you can't easily change the display order.
Text("Abs").tag(Part.abs)
Text("Legs").tag(Part.legs)
Text("Push").tag(Part.push)
Text("Pull").tag(Part.pull)
Text("Full Body").tag(Part.fullBody)
}.pickerStyle(.segmented)
ExerciseListView(predicate:config.predicate)
}
}
}
}
struct ExerciseListView: View {
// var part: String
let predicate: NSPredicate?
// @FetchRequest var exercises: FetchedResults<Exercise>
init(predicate: NSPredicate?) {
self.predicate = predicate
// self._exercises = FetchRequest(
// entity: Exercise.entity(),
// sortDescriptors: [],
//
// predicate: NSPredicate(format: "musclegroup == %@", part as any CVarArg)
// )
}
var body: some View {
Text(predicate?.description ?? "")
// List(exercises) { e in
// Text(e.exercisename)
// }
}
}
Since you are using Core Data you might want to use an Int enum in the entity for less storage and faster queries.