Декодировать координаты 2D-многоугольника, используя протокол Struct's Encodable - PullRequest
0 голосов
/ 08 октября 2018

Я пытаюсь проанализировать приведенный ниже json, используя кодируемый протокол Swift Struct.Если я сделаю координаты Any или AnyObject, это выдаст ошибку, сказав, что не соответствует протоколу.

Я знаю, что этого можно достичь с помощью массивов и словарей, но я не хочу делать это таким образом.

{
    "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 голосов
/ 08 октября 2018

Я предлагаю сделать так, чтобы 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]]
}
0 голосов
/ 08 октября 2018

Фрагмент данных, который вы представили в исходном вопросе (до того, как вы несколько раз редактировали его после прочтения моих комментариев), был недействительным JSON.Если вы поместите фигурные скобки вокруг всего (что у вас есть сейчас), это будет действительный объект JSON с полем «координаты».Но из вашего (оригинального) вопроса я понимаю, что это, вероятно, не то, что вы хотите.Следующей лучшей вещью, которую вы можете получить, которая является действительной JSON, будет Array (т. Е. Содержимое поля 'координаты').

Следующий фрагмент кода дает объект 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]]])

Если вы удалите комментарии в коде примера, вы получите массив без фигурных скобок, но также без «координат»: label (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]]])
...