使用Struct的Encodable协议解码2D多边形坐标

时间:2018-10-08 12:03:04

标签: arrays swift struct codable

我正在尝试使用Swift Struct的Encodable协议解析以下json。 如果我将坐标设为AnyAnyObject,则会出现错误,提示您不符合协议。

我知道可以使用数组和字典来实现,但是我不想那样做。

{
    "coordinates": [
        [
            [
                0.148271,
                51.6723432
            ],
            [
                0.148271,
                51.3849401
            ],
            [
                -0.3514683,
                51.3849401
            ],
            [
                -0.3514683,
                51.6723432
            ],
            [
                0.148271,
                51.6723432
            ]
        ]
    ]
} 

struct Geometry: Codable {
    let coordinates: [[[Double]]]

    init(from decoder: Decoder) throws {
        let data = try decoder.container(keyedBy: CodingKeys.self)
        coordinates = try data.decode([[[Double]]].self, forKey: .coordinates)
    }
}

do {
    let decoded = try JSONDecoder().decode(Geometry.self, from: data!)
    print(decoded)
    completionHandler(statusCode, decoded)
} catch {
    print("Failed to encode data.")
    completionHandler(statusCode, nil)
}

如何解决此问题?

2 个答案:

答案 0 :(得分:1)

我的建议是使CLLocationCoordinate2D符合Codable解码Double的数组

import CoreLocation

extension CLLocationCoordinate2D : Codable {
    public init(from decoder: Decoder) throws {
        var arrayContainer = try decoder.unkeyedContainer()
        if arrayContainer.count == 2 {
            let lat = try arrayContainer.decode(CLLocationDegrees.self)
            let lng = try arrayContainer.decode(CLLocationDegrees.self)
            self.init(latitude: lat, longitude: lng)
        } else {
            throw DecodingError.dataCorruptedError(in: arrayContainer, debugDescription: "Coordinate array must contain two items")
        }
    }

    public func encode(to encoder: Encoder) throws {
        var arrayContainer = encoder.unkeyedContainer()
        try arrayContainer.encode(contentsOf: [latitude, longitude])
    }
}

然后您可以简单地声明Geometry

struct Geometry: Codable {
    let coordinates: [[CLLocationCoordinate2D]]
}

答案 1 :(得分:-1)

您在原始问题中呈现的数据段(在阅读我的评论后多次编辑之前)不是有效的JSON。 如果在所有内容(现在都拥有)周围加上大括号,则它将是带有“ coordinates”字段的有效JSON对象。但是从您的(原始)问题中我知道那可能不是您想要的。可以得到的第二个最好的东西是有效的JSON是Array(即“ coordinates”字段的内容。)

以下代码段提供了JSON对象:

import Foundation

let sample  = [[[0.148271, 51.6723432], [0.148272, 51.6723433], [0.148273, 51.6723434],]]

struct Geometry: Codable {
    var coordinates: [[[Double]]]

    init(coord: [[[Double]]]) {
        self.coordinates = coord
    }

////  Remove the comments below in order use a simple JSON array!
//    func encode(to encoder: Encoder) throws {
//        var container = encoder.singleValueContainer()
//        try container.encode(coordinates)
//    }
//
//    init(from decoder: Decoder) throws {
//        let container = try decoder.singleValueContainer()
//        coordinates = try container.decode([[[Double]]].self)
//    }
}

// Initialize a Geometry object
let geo = Geometry(coord: sample)

// Serialize into `data` and print the result
let data = try! JSONEncoder().encode(geo)
print (String(data: data, encoding: .utf8) ?? "-not representable-")

// Now, decode the data into a new Geometry instance `g` and print it
let g = try! JSONDecoder().decode(Geometry.self, from: data)
print (g)

这导致(JSON格式具有更好的可读性):

{
  "coordinates": [
    [
      [
        0.14827099999999999,
        51.6723432
      ],
      [
        0.14827199999999999,
        51.672343300000001
      ],
      [
        0.14827299999999999,
        51.672343400000003
      ]
    ]
  ]
}

Geometry(coordinates: [[[0.148271, 51.6723432], [0.148272, 51.6723433], [0.148273, 51.6723434]]])

如果删除示例代码中的注释,则得到的数组不带花括号,但不带“ coordinates”:标签(JSON格式具有更好的可读性):

[
  [
    [
      0.14827099999999999,
      51.6723432
    ],
    [
      0.14827199999999999,
      51.672343300000001
    ],
    [
      0.14827299999999999,
      51.672343400000003
    ]
  ]
]

Geometry(coordinates: [[[0.148271, 51.6723432], [0.148272, 51.6723433], [0.148273, 51.6723434]]])