使用 Struct 的 Encodable 协议解码二维多边形坐标
Decode 2D Polygon coordinates using Struct's Encodable protocol
我正在尝试使用 Swift 结构的 Encodable 协议解析以下 json。
如果我将坐标设置为 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)
}
如何解决这个问题?
您在原始问题中提供的数据片段(在阅读我的评论后多次编辑之前)无效 JSON。
如果你把所有东西(你现在拥有的)都放在大括号中,它将是一个有效的 JSON 对象,带有 'coordinates' 字段。但是从您的(原始)问题来看,我了解到这可能不是您想要的。下一个有效的 JSON 是数组(即 '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]]])
我的建议是让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]]
}
我正在尝试使用 Swift 结构的 Encodable 协议解析以下 json。
如果我将坐标设置为 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)
}
如何解决这个问题?
您在原始问题中提供的数据片段(在阅读我的评论后多次编辑之前)无效 JSON。 如果你把所有东西(你现在拥有的)都放在大括号中,它将是一个有效的 JSON 对象,带有 'coordinates' 字段。但是从您的(原始)问题来看,我了解到这可能不是您想要的。下一个有效的 JSON 是数组(即 '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]]])
我的建议是让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]]
}