jsonswiftswiftuiswiftui-listswiftui-state

SwiftUI: Instance member 'enableFilter' cannot be used on type 'ContentView'; did you mean to use a value of this type instead?


I'm a beginner with SwiftUI and I wanted to create a dynamic list with the birthdays of people. I also wanted to integrate a filter that facilitates to find birthdays. But in the lines:

if enableFilter == true {
    return json.filter {$0.BirthdayString.contains(filter(date: filterDate))}
} else {
   return json
}

I always get these errors:

Instance member 'enableFilter' cannot be used on type 'ContentView'; did you mean to use a value of this type instead?

and

Instance member 'filterDate' cannot be used on type 'ContentView'; did you mean to use a value of this type instead?

I think I understand why the errors are present but I don't no how to fix it. I tried:

@State static var

but then I cannot change the values with my

filterView

Thank you for your help, here is the full source code:

import SwiftUI

struct person: Codable, Hashable, Identifiable {
    var id: Int
    var Birthday: Date
    var BirthdayString: String
}

func filter(date: Date) -> String {
    let DateComponents = Calendar.current.dateComponents([.year, .month, .day], from: date)
   let DateComponentsString: String = "\(DateComponents.day)/\(DateComponents.month)/\(DateComponents.year)"
    
    return DateComponentsString
}

struct ContentView: View {
    
    @State var people: [person] = {
        guard let data = UserDefaults.standard.data(forKey: "people") else { return [] }
        if let json = try? JSONDecoder().decode([person].self, from: data) {
            if enableFilter == true {
                return json.filter {$0.BirthdayString.contains(filter(date: filterDate))}
            } else {
                return json
            }
        }
        return []
    }()

@State var filterDate: Date = Date()
@State var enableFilter: Bool = false

@State var showFilter: Bool = false
@State var newPersonDate: Date = Date()
    
    var body: some View {
        NavigationView {
            VStack {
                
                HStack {
                    DatePicker(selection: $newPersonDate, label: {Text("Birthday")}).padding()
                    
                    Button(action: {didTapAddTask()}, label: {Text("Add")}).padding()
                }
                
            List {
                ForEach($people) { $person in
                    Text("\(person.Birthday)")
                }
            }
        }
            .navigationTitle(Text("People's birthday"))
        }
    }
    
    var filterView: some View {
        VStack {
            DatePicker(selection: $filterDate, label: {Text("Date")}).padding()
            Toggle(isOn: $enableFilter, label: {Text("enable filter")}).padding()
        }
    }
    
    func didTapAddTask() {
    let id = people.reduce(0) { max($0, $1.id) } + 1
    people.insert(person(id: id, Birthday: newPersonDate, BirthdayString: filter(date: newPersonDate)), at: 0)
    newPersonDate = Date()
    save()
    }
                                                 
    func save() {
        guard let data = try? JSONEncoder().encode(people) else { return }
    UserDefaults.standard.set(data, forKey: "people")
    }
    }


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Solution

  • You can use another Computed property which will get the data based on some another property's value. i.e enableFilter.

    @State var people: [person]  = {
            guard let data = UserDefaults.standard.data(forKey: "people") else { return [] }
            if let json = try? JSONDecoder().decode([person].self, from: data) {
                return json
            }
            return []
    }()
    
    var data : [person] {
        if enableFilter {
            return people.filter {$0.BirthdayString.contains(filter(date: filterDate))}
        } else {
            return people
        }
    }
    

    And use this property to get the relevant data:

    var body: some View {
        NavigationView {
            VStack {
                HStack {
                    DatePicker(selection: $newPersonDate, label: {Text("Birthday")}).padding()
                    Button(action: {didTapAddTask()}, label: {Text("Add")}).padding()
                }
            List {
                ForEach(data) { person in   // <<--- Here `data`
                    Text("\(person.Birthday)")
                }
            }
        }
            .navigationTitle(Text("People's birthday"))
        }
    }