Swift中GeoJSONFeatureCollection无法编码,需遵循Encodable协议
问题解决:GeoJSONFeatureCollection 不遵循 Encodable 协议的处理方案
你遇到的错误核心是你使用的GeoJSONFeatureCollection类型没有实现Encodable协议,导致JSONEncoder.encode()无法直接序列化它。以下是几种实用的解决办法:
方法1:用JSONSerialization直接序列化字典(最快捷)
很多GeoJSON库自带字典转义方法,直接基于字典生成JSON数据即可,不用依赖JSONEncoder:
import GeoJSON import MapKit let coordArray: [CLLocationCoordinate2D] = [ CLLocationCoordinate2D(latitude: 77, longitude: 44), CLLocationCoordinate2D(latitude: 78, longitude: 45), CLLocationCoordinate2D(latitude: 79, longitude: 46) ] // 生成LineString的字典表示 let way = GeoJSONLineString(coordinates: coordArray) let lineStringDict = way.dictionaryRepresentation // 手动构造符合GeoJSON规范的FeatureCollection字典 let featureCollectionDict: [String: Any] = [ "type": "FeatureCollection", "features": [ [ "type": "Feature", "geometry": lineStringDict, "properties": [:] // 这里可以添加自定义属性,比如["name": "测试路线"] ] ] ] // 转成JSON数据/字符串 do { let jsonData = try JSONSerialization.data(withJSONObject: featureCollectionDict, options: .prettyPrinted) if let jsonString = String(data: jsonData, encoding: .utf8) { print(jsonString) } } catch { print(error.localizedDescription) }
方法2:给GeoJSON类型扩展Encodable协议(自定义适配)
如果想继续用JSONEncoder,可以给库中的核心类型手动扩展Encodable协议:
import GeoJSON import MapKit // 给GeoJSONFeatureCollection扩展Encodable extension GeoJSONFeatureCollection: Encodable { enum CodingKeys: String, CodingKey { case type, features } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode("FeatureCollection", forKey: .type) try container.encode(features, forKey: .features) } } // 给GeoJSONFeature扩展Encodable extension GeoJSONFeature: Encodable { enum CodingKeys: String, CodingKey { case type, geometry, properties } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode("Feature", forKey: .type) try container.encode(geometry, forKey: .geometry) try container.encode(properties, forKey: .properties) } } // 给GeoJSONLineString扩展Encodable extension GeoJSONLineString: Encodable { enum CodingKeys: String, CodingKey { case type, coordinates } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode("LineString", forKey: .type) // 把CLLocationCoordinate2D转成GeoJSON要求的[经度,纬度]数组格式 let coords = coordinates.map { [$0.longitude, $0.latitude] } try container.encode(coords, forKey: .coordinates) } } // 现在可以正常使用JSONEncoder了 do { let coordArray: [CLLocationCoordinate2D] = [ CLLocationCoordinate2D(latitude: 77, longitude: 44), CLLocationCoordinate2D(latitude: 78, longitude: 45), CLLocationCoordinate2D(latitude: 79, longitude: 46) ] let lineString = GeoJSONLineString(coordinates: coordArray) let feature = GeoJSONFeature(geometry: .lineString(lineString), properties: [:]) let featureCollection = GeoJSONFeatureCollection(features: [feature]) let jsonData = try JSONEncoder().encode(featureCollection) if let jsonString = String(data: jsonData, encoding: .utf8) { print(jsonString) } } catch { print(error.localizedDescription) }
方法3:更换支持Codable的GeoJSON库
如果不想自己写扩展,可以换用原生支持Codable协议的GeoJSON库(比如SwiftGeoJSON),这类库开箱即用,直接用JSONEncoder序列化即可。
额外注意
你原代码中GeoJSONFeatureCollection(dictionary: way.dictionaryRepresentation)的写法是错误的——way.dictionaryRepresentation是LineString的字典,而FeatureCollection需要包含type和features字段的结构,直接传入会导致GeoJSON格式不合法,上面的方案已经修正了这个问题。
内容的提问来源于stack exchange,提问作者user18624814
相关产品推荐
相关产品推荐

