可分解码不适用于非空数组

时间:2019-09-21 16:43:14

标签: swift collections

我正在使用这个库,它创建了非空集合,如数组,字典和字符串。 https://github.com/pointfreeco/swift-nonempty

当我解码到非空数组时,出现以下错误

Swift.DecodingError.typeMismatch(Swift.Dictionary,Swift.DecodingError.Context(codingPath:[CodingKeys(stringValue:“ poiList”,intValue:nil)]],debugDescription:“希望对Dictionary进行解码,但找到了一个数组。” ,underlyingError: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 个答案:

答案 0 :(得分:1)

由于JSONDecoder不了解init(from:)及其初始化方式,因此您需要对顶部结构拥有自己的NonEmpty。除了初始化之外,我还添加了编码键和一个新错误

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)
    }
    //...
}

答案 1 :(得分:0)

您可以尝试

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)