2
votes

I try to decode data from Google API server, and they always get to mo error like

typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "rows", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "elements", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "distance", intValue: nil)], debugDescription: "Expected to decode Array but found a dictionary instead.", underlyingError: nil))

I don't have any variants of realization of this

{
    "destination_addresses": [
        "Абая-Саина, просп. Абая, Алматы, Казахстан"
    ],
    "origin_addresses": [
        "г. Алматы, ул. Джандосова, 6, уг. ул. Манаса, Алматы, Казахстан"
    ],
    "rows": [
        {
            "elements": [
                {
                    "distance": {
                        "text": "7,2 км",
                        "value": 7241
                    },
                    "duration": {
                        "text": "16 мин.",
                        "value": 980
                    },
                    "status": "OK"
                }
            ]
        }
    ],
    "status": "OK"
}

this is my key structure

struct Distance:Codable {
    var destination_addresses  : [String]?
    var origin_addresses : [String]?
    var rows : [row]?
    var status : String?
    enum CodingKeys:String,CodingKey{
        case destination_addresses = "destination_addresses"
        case origin_addresses = "origin_addresses"
        case rows = "rows"
        case status = "status"
    }
}

struct row:Codable {
    var elements : [elements]?
    enum CodingKeys:String,CodingKey {
        case elements = "elements"
    }
}
struct elements:Codable {
    var distance : [distance]?
    var duration : [duration]?
    var status : String?
    enum CodingKeys:String,CodingKey {
        case distance = "distance"
        case duration = "duration"
        case status = "status"
    }
}
struct distance:Codable {
    var text : String?
    var value : Int?
    enum CodingKeys:String,CodingKey {
        case text = "text"
        case value = "value"
    }
}
struct duration:Codable {
    var text : String?
    var value : Int?
    enum CodingKeys:String,CodingKey {
        case text = "text"
        case value = "value"
    }
}

My decoding

        let root = try decoder.decode(Distance.self, from: data)
1
If names in JSON match names in your Codable type you don't need to define CodingKey type. And if case names of enum with String raw value match string values you don't need to write it down.user28434'mstep
It is Swift naming convention to name your structures starting with an uppercase letterLeo Dabus
This Website generates the needed Swift code from your JSON. Might be helpfulDoesData

1 Answers

0
votes

You can try

struct Root: Codable {
    let destinationAddresses, originAddresses: [String]
    let rows: [Row]
    let status: String

    enum CodingKeys: String, CodingKey {
        case destinationAddresses = "destination_addresses"
        case originAddresses = "origin_addresses"
        case rows, status
    }
}

struct Row: Codable {
    let elements: [Element]
}

struct Element: Codable {
    let distance, duration: Distance // your problem is here
    let status: String
}

struct Distance: Codable {
    let text: String
    let value: Int
}

let root = try? decoder.decode(Root.self, from: data)

as

var distance : [distance]?
var duration : [duration]?

are dictionaries not arrays

Also no need to create 2 strcuts for the same content distance and duration only 1 suffices as the point is in changing the key only

In addition don't use enum CodingKeys: String, CodingKey { in a struct if you won't change key names as it would be useless