Search code examples
iosswiftxcodeswift-keypath

SwiftUI Can't Pass String to KeyPath


I have an app that references a large dataset that I load from an external public site as a comma separated value file. I parse the data to a an array of a model called WaterPointModel. An abbreviated version is:

struct WaterPointModel: Identifiable {

    let id = UUID()

    let STATE: String
    let COUNTY: String
    let AQWFrTo: Double
    let AQWGWSa: Double
    let AQWGWTo: Double
    //many more
}

I then want to summarize(reduce) the data. My function for this is:

func sumOnAttributeUSList(sumField: KeyPath<WaterPointModel,Double>) -> Double {
    return dataStore.waterPointModels.map({ $0[keyPath:sumField] }).reduce(0, +)
}

Next I want to call this to build a report:

let aqWFrTo = sumOnAttributeUSList(sumField: \.AQWFrTo)    

This all works. However there are other reports where I need to pass a string to create that keypath. Say I have a lookup table where I lookup "abc" and get "AQWFrTo". I would like to do something like this in a loop:

let abc = "AQWFrTo"
let aqWFrTo = sumOnAttributeUSList(sumField: \WaterPointModel.abc)

I have not been able to make any version of this work. Any guidance would be appreciated.

Xcode 13.3.1, iOS 15.4


Solution

  • A simple approach is this:

    func toKeypath(_ str: String) -> KeyPath<WaterPointModel,Double>? {  // <-- with or without optional
        switch str {
            case "AQWFrTo": return \.AQWFrTo
            case "AQWGWSa": return \.AQWGWSa
            case "AQWGWTo": return \.AQWGWTo
            // ...
            default: return nil  // <-- or a default Keypath
        }
    }
    
    let aqWFrTo = sumOnAttributeUSList(sumField: toKeypath("AQWFrTo"))