我不建议子类化MKPolygon。坦率地说,我根本不建议创建 CustomPolygon 和 Coordinate。无需引入镜像原生 MKPolygon 和 CLLocationCoordinate2D 类型的类型。
与其尝试创建可编码的MKPolygon,不如建议创建一个仅表示坐标集合的Codable 类型,该类型对纬度和经度数组进行编码。
但首先,让我们考虑一个 JSON 结构,一个坐标数组:
[
{"longitude":37.785834, "latitude":-122.406417},
{"longitude":37.246878, "latitude":-122.245676},
...
]
因此,我将创建一个编码/解码类型,如Encoding and Decoding Custom Types 的“手动编码和解码”部分所述:
struct Coordinates: Codable {
var coordinates: [CLLocationCoordinate2D] = []
// MARK: Codable
enum CodingKeys: String, CodingKey {
case latitude, longitude
}
init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
while !container.isAtEnd {
let subcontainer = try container.nestedContainer(keyedBy: CodingKeys.self)
let latitude = try subcontainer.decode(CLLocationDegrees.self, forKey: .latitude)
let longitude = try subcontainer.decode(CLLocationDegrees.self, forKey: .longitude)
coordinates.append(CLLocationCoordinate2D(latitude: latitude, longitude: longitude))
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
for value in coordinates {
var subcontainer = container.nestedContainer(keyedBy: CodingKeys.self)
try subcontainer.encode(value.latitude, forKey: .latitude)
try subcontainer.encode(value.longitude, forKey: .longitude)
}
}
}
我还可以创建一些方便的方法来轻松地从Coordinates 创建MKPolygon 和MKPolyline,反之亦然:
extension Coordinates {
init(from polygon: MKPolygon) {
self.polygon = polygon
}
init(from polyline: MKPolyline) {
self.polyline = polyline
}
var polygon: MKPolygon {
get { MKPolygon(coordinates: coordinates, count: coordinates.count) }
set { updateCoordinates(from: newValue) }
}
var polyline: MKPolyline {
get { MKPolyline(coordinates: coordinates, count: coordinates.count) }
set { updateCoordinates(from: newValue) }
}
private mutating func updateCoordinates(from shape: MKMultiPoint) {
let pointCount = shape.pointCount
coordinates = .init(repeating: kCLLocationCoordinate2DInvalid, count: pointCount)
shape.getCoordinates(&coordinates, range: NSRange(location: 0, length: pointCount))
}
}
extension MKPolyline {
var coordinates: Coordinates { Coordinates(from: self) }
}
extension MKPolygon {
var coordinates: Coordinates { Coordinates(from: self) }
}
那么,如果你想编码一个多边形的坐标:
let coordinates = polygon.coordinates // if you need to extract the `Coordinates` collection from the `MKPolygon`
let data = try JSONEncoder().encode(coordinates)
或者,如果您想解码坐标并从中创建一个MKPolygon:
let coordinates = try JSONDecoder().decode(Coordinates.self, from: data)
let polygon = coordinates.polygon // if you want to add a `MKPolygon` represented by this collection of `Coordinates`
但想法是,您的模型对象将是 Coordinates 类型(即 CLLocationCoordinate2d 的集合),即 Codable。然后,您可以使用 polygon 或 polyline 计算属性来构建适当的 MKOverlay 类型,然后您可以将其添加到地图中。
因为Coordinates 是Codable,你现在可以在你自己的Codable 类型中使用这个类型,例如:
struct RegionOfInterest: Codable {
let name: String
let coordinates: Coordinates
}