You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 15:57:51