Search code examples
swiftstructjsondecoder

Swift - How to change JSON Struct Element Values


I have converted JSON data file to a deviceParameters instance of Struct using JSONDocode and it works fine. However I am struggling to change the values of properties on the Struct programmatically afterwards. Any Suggestings?

struct DeviceParameters : Codable, Hashable {
    
    let id : String
    let version : String
    let encoding : String
    let deviceType : String // name of XML file is converted to deviceName, unique identifier
    var Point : [PointData]
    
    enum CodingKeys: String, CodingKey {
        case id, version, encoding, Point
        case deviceType = "name"
    }
}

struct PointData : Codable, Hashable {
    let id : String
    var name : String
    let type : String
    var address : Address
    let calculate : Calculate
    let pointEnum: [String: String]
    var presentValue : String
    
    enum CodingKeys: String, CodingKey {
        case id, name
        case type = "Type"
        case address = "Address"
        case calculate = "Calculate"
        case pointEnum = "Enum"
        case presentValue
    }
    
}

struct Calculate: Codable, Hashable {
    let scaling, decimals, min, max: String?
}

struct Address: Codable, Hashable {
    var index: String
    let type: String
    let format: String
}

Using ForEach I can scroll print the struct parameters, but I cannot assign new values to the variables. What is the correct way for this? And perhaps the simplest?

func updatePresentValue(pointNo : Int) {
    
    deviceParameters.Point.forEach {
        print($0.name) // prints the name of the "Point" OK
        print($0.address.index) // prints the name of the "Point.Address" OK
        $0.presentValue = "200" // Not working telling $0 inmutable
        $0.address.index = "20"  // Not working telling $0 inmutable
    }
}

Solution

  • Firstly make sure you name your variables starting with a lowercase letter, that is an accepted coding practice.

    Closure parameters are immutable, you cannot assign a new value. But you could use a map operator where you make a copy of your struct, assign new values and return that copy in your closure.

    func updatePresentValue(pointNo : Int) {
        deviceParameters.points = deviceParameters.points.map { point in
            var p = point
            p.address.index = "New value"
            return p
        }
    }