Как пользовательским декодировать каждый элемент массива с помощью Swift Decodable - PullRequest
0 голосов
/ 03 января 2019

Я декодирую ответ JSON погоды и хочу передать информацию в дочерний декодер, который будет декодировать массив.Как я могу передать эту информацию для каждого элемента массива JSON при декодировании с помощью Swift Decodable?

Я пытаюсь сделать это в последней версии Swift (4.2), и я уже реализовал необходимый код дляуспешно пользовательское декодирование той же модели, которая используется в массиве.Мне не удалось декодировать весь массив.

struct DataBlock: Decodable {
    /..
    let weather: [DataPoint]?

    init(from decoder: Decoder) throws {
        try self.init(from: decoder, units: .unit)
    }

    init(from decoder: Decoder, units: Units) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        /..
        let nestedDecoder = try values.superDecoder(forKey: .weather)
        self.weather = try [DataPoint(from: nestedDecoder, units: units)]
    }

    enum CodingKeys: String, CodingKey {
        /..
        case weather
    }
}

И в модели DataPoint:

init(from decoder: Decoder, units: Units) throws {
    let values = try decoder.container(keyedBy: CodingKeys.self)
    /...
    if let value = try values.decodeIfPresent(Double.self, forKey: .value) {
        self.value = Example(value: value, units: units)
    } else {
        self.value = nil
    }
    /..
}

Соответствующая часть структуры JSON, которую я пытаюсь декодировать:

"datablock": {
    "weather": [
        {
            /..
            "value": 22.72
            /..
        }
    ]
}

Я ожидаю, что декодер передаст

units

и декодирует каждый элемент массива вручную.

Однако я получаю ошибку отладки:

"Expected to decode Dictionary<String, Any> but found an array instead."

Ошибка вызывается здесь:

self.weather = try [DataPoint(from: nestedDecoder, units: units)]

1 Ответ

0 голосов
/ 04 января 2019

Это решает мою проблему, позволяя мне «проходить» каждый элемент массива JSON и декодировать каждый отдельно:

struct DataBlock: Decodable {
    /..    
    init(from decoder: Decoder, units: Units) throws {
        /..
        var data = [DataPoint]()
        var dataContainer = try values.nestedUnkeyedContainer(forKey: .data)

        while !dataContainer.isAtEnd {
            let nestedDecoder = try dataContainer.superDecoder()
            let dataPoint = try DataPoint(from: nestedDecoder, units: units)
            data.append(dataPoint)
        }

        self.data = data
        /..
    }
    /..
}
...