Decodable не работает с не пустым массивом - PullRequest
1 голос
/ 21 сентября 2019

Я использую эту библиотеку, которая создала непустые коллекции, такие как массивы, словари и строки.https://github.com/pointfreeco/swift-nonempty

Когда я декодирую в непустой массив, я получаю следующую ошибку

Swift.DecodingError.typeMismatch (Swift.Dictionary, Swift.DecodingError.Context (codingPath: [CodingKeys (stringValue: "poiList", intValue: nil)], debugDescription: "Ожидается декодировать словарь, но вместо него найден массив.", underError: nil))

Это моя структура

struct LocationCarModel: Codable {

    // MARK: - Properties
    var poiList: NonEmptyArray<PointOfInterest>

    // MARK: - PointOfInterest
    struct PointOfInterest: Codable {
        var id: Int
        var coordinate: Position
        var fleetType: String
        let numberPlate = "HCD837EC"
        let model: String = "Tesla S"
        let fuel: Double = 0.9
    }
}

Это ответ, который я получаю https://fake -poi-api.mytaxi.com /? P2Lat = 53.394655 & p1Lon = 9.757589 & p1Lat = 53.694865 & p2Lon = 10.099891

и вот как яЯ декодирую его.

 public extension Decodable {

   static func parse(from item: Any?, strategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) -> Self? {

       guard let data = self.data(from: item) else {
           return nil
       }

       let decoder = JSONDecoder()
       decoder.keyDecodingStrategy = strategy

       do {
           let result = try decoder.decode(Self.self, from: data)
           return result
       } catch {
           debugPrint(error)
           return nil
       }
   }

   private static func data(from item: Any?) -> Data? {
       switch item {
       case let data as Data:
           return data
       case let string as String:
           return string.data(using: .utf8)
       case .some(let item):
           return try? JSONSerialization.data(withJSONObject: item, options: [])
       case nil:
           return nil
       }
   }
}

, и строка для декодирования с использованием вышеуказанной функции:

let model = LocationCarModel.parse(from: data)

Если изменить poiList на стандартный массив swift, то ошибка не возникнет.

Есть идеи, как я могу решить эту проблему?Любая помощь будет оценена.Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 22 сентября 2019

Вам нужно иметь свой собственный init(from:) для верхней структуры, так как JSONDecoder не понимает NonEmpty и как его инициализировать.Помимо init я также добавил ключи кодирования и новую ошибку

enum DecodeError: Error {
    case arrayIsEmptyError
}

struct LocationCarModel: Codable {
    var poiList: NonEmpty<[PointOfInterest]>

    enum CodingKeys: String, CodingKey {
        case poiList
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let array = try container.decode([PointOfInterest].self, forKey: .poiList)
        guard let first = array.first else {
            throw DecodeError.arrayIsEmptyError
        }
        poiList = NonEmptyArray(first, array)
    }
    //...
}
0 голосов
/ 21 сентября 2019

Можно попробовать

struct Root: Codable {
    let poiList: [PoiList]
}

// MARK: - PoiList
struct PoiList: Codable {
    let id: Int
    let coordinate: Coordinate
    let fleetType: String
    let heading: Double
}

// MARK: - Coordinate
struct Coordinate: Codable {
    let latitude, longitude: Double
}

let res = try? JSONDecoder().decode(Root.self,from:data)
print(res)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...