Frans-Jan Wind
Frans-Jan Wind

Reputation: 11

Swift set struct property with name in variable

After loading a json in a codable struct I'd like to change values dynamicly. I already can change a targeted value this way:

let setThisValue = 0.6
setConfig.instrumentsConfig[0].effects![0].feedback!.setValue(value: setThisValue)

Given these structs:

struct InstrumentConfig: Codable{
    let trackId: String
    var effects: [Effects]?
}

struct Effects: Codable{
    
    let effectName: String
    var dryWetMix: ValueAndRange?
    var resonance: ValueAndRange?
    var cutoffFrequency: ValueAndRange?
}

struct ValueAndRange: Codable{
    var value: Double
    var range: [Double]
 
    mutating func setValue(value: Double){
        self.value = value
    }
}

Since I'm loading data which can contain various property names I'd like to iterate trough all properties and set the correct one. I do know the index of the property i.e. resonance has index 2.

This is how this unknown function could be called, where ????[2] is the unknown part

let setThisValue = 0.6
let effectPropperty: String = "feedback"
let effectProppertyIndex = 2

setConfig.instrumentsConfig[0].effects![0].????[2]!.setValue(value: setThisValue)

Thank you for any ideas about this.

Upvotes: 0

Views: 1245

Answers (2)

Rob Napier
Rob Napier

Reputation: 299663

There are a lot of ways to implement this, but most of them are going to use @dynamicMemberLookup at some point. A simple way is like this:

@dynamicMemberLookup
struct Effects: Decodable {
    let effectName: String
    var dryWetMix: ValueAndRange?
    var resonance: ValueAndRange?
    var cutoffFrequency: ValueAndRange?

    private static let keyMap = [
        "dryWetMix": \Self.dryWetMix,
        "resonance": \Self.resonance,
        "cutoffFrequency": \Self.cutoffFrequency,
    ]

    subscript(dynamicMember key: String) -> ValueAndRange? {
        get { Self.keyMap[key].flatMap { self[keyPath: $0] } }
        set { Self.keyMap[key].map { self[keyPath: $0] = newValue } }
    }
}

A key requirement is that all of your dynamic keys need to be of the same type (ValueAndRange? in this case).

Upvotes: 2

Ptit Xav
Ptit Xav

Reputation: 3219

You can use the Array method firstIndex(where:) :

let index = setConfig.instrumentsConfig[0].effects?.firstIndex {
$0.effectName == effectProperty

}

Upvotes: 0

Related Questions