Home > OS >  Saving User Data to Array inside Struct
Saving User Data to Array inside Struct

Time:03-23

I'd like to properly save inputted user data / variables inside an array which is inside a struct but unable to get it to work.

Currently, I have a few structs:

struct Household: Codable {
    let id  = UUID()
    var region: String
    var householdSize: Int = 1
    var receivingBenefits: [String]
    var energyCrisis: Bool
    var utilityProviders: [String]
    var residenceType: String
    var propertyTaxPastDue, homeNeedsRepairs, filedPreviousYearTaxReturn, heatingSystemNeedsRepairs: Bool
    var atRiskOfHomelessness: Bool
    var receivedMaximumBenefit: ReceivedMaximumBenefit
    var personDetails: [PersonDetail]
    var incomes: [Income]
    var assets: [Asset]

    enum CodingKeys: String, CodingKey {
        case region
        case householdSize = "household_size"
        case receivingBenefits = "receiving_benefits"
        case energyCrisis = "energy_crisis"
        case utilityProviders = "utility_providers"
        case residenceType = "residence_type"
        case propertyTaxPastDue = "property_tax_past_due"
        case homeNeedsRepairs = "home_needs_repairs"
        case filedPreviousYearTaxReturn = "filed_previous_year_tax_return"
        case heatingSystemNeedsRepairs = "heating_system_needs_repairs"
        case atRiskOfHomelessness = "at_risk_of_homelessness"
        case receivedMaximumBenefit = "received_maximum_benefit"
        case personDetails = "person_details"
        case incomes, assets
    }
}

struct PersonDetail: Codable, Identifiable {

    let id  = UUID()  // <-- here
    var age: Int = 18
    var maritalStatus: String = ""
    var minimumEmploymentOverExtendedPeriod: Bool
    var workStatus: String = ""
    var pregnant: Bool
    var attendingSchool: Bool = false
    var disabled: Bool

    enum CodingKeys: String, CodingKey {
        case age
        case maritalStatus = "marital_status"
        case minimumEmploymentOverExtendedPeriod = "minimum_employment_over_extended_period"
        case workStatus = "work_status"
        case pregnant
        case attendingSchool = "attending_school"
        case disabled
    }
}

class Base: ObservableObject, Codable {
    @Published var household: Household

    enum CodingKeys: String, CodingKey {
        case household = "household"
    }
}

Now, I can easily bind a Textfield, toggle or Picker to anything under the Household struct for example below which I believe is easily connected via household in the Base() class..

HStack() {
   Image(systemName:"wrench.and.screwdriver.fill")
               .frame(width: 15, height: 15)
  Toggle(isOn: $eligBase.household.homeNeedsRepairs) {
           Text("Need Home Repairs?")
                   .font(.system(size: 15))
              }.tint(.blue)
          }

However, I'm unable to connect anything in the array`[PersonDetail], which I included the struct.

For example, If I wanted to connected a Toggle for the disabled variable in `PersonDetail', I get an error, here is my disabled toggle:

 Toggle(isOn: $eligBase.household.personDetails.disabled) {
              Text("Disabled")
                        .font(.system(size: 15))
......
}

I receive an error stating:

Value of type 'Binding<[PersonDetail]>' has no dynamic member 'disabled' using key path from root type '[PersonDetail]'

Any ideas how I can connect Toggles, Textfield, Picker to a variable in an array which is in a struct?

CodePudding user response:

You are trying to bind the control to the whole array of PersonDetail, not an individual entry within the array.

For example, if you always wanted to use the first personDetail instance in the array:

Toggle(isOn: $eligBase.household.personDetails.first!.disabled) {
              Text("Disabled")
                        .font(.system(size: 15))

In a real solution you'd probably want to safely unwrap whatever PersonDetail instance you want in the array, and cleanly handle the array being empty (as the forced unwrap in my example would crash if the array was empty).

CodePudding user response:

You can use a List for your array of PersonDetail, such as in this example code:

struct ContentView: View {
    @StateObject var eligBase = Base()
    
    var body: some View {
        VStack {
            List {
                Section("Person Details") {
                    ForEach($eligBase.household.personDetails) { $person in
                        TextField("", text: $person.maritalStatus)
                        Toggle(isOn: $person.disabled) {
                            Text("Disabled")
                        }
                    }
                }
            }
        }
    }
} 
  • Related