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

如何将GEOSwift.JSON转换为Swift中的自定义结构体

如何将GEOSwift.JSON对象转换为自定义Decodable结构体

问题背景

我有如下GEOSwift Feature结构:

{
  "type" : "Feature",
  "geometry" : {
    "type" : "Point",
    "coordinates" : [
      -xx.xxxxxxxxxxxxxxx,
      xx.xxxxxxxxxxxxxxx
    ]
  },
  "properties" : {
    "mapLayer" : "MyMapLayer",
    "data" : {
      "id" : 42,
      "sizeClass" : "Large",
      // 其他字段...
    },
    "featureType" : "MyFeatureType"
  }
}

需要提取其中的data字段,转换为自定义的MyStruct结构体:

struct MyStruct: Decodable {
    var id: Int
    var sizeClass: String?
    // 其他字段...
}

目前能通过以下代码获取到data,但它的类型是GEOSwift.JSON,不知道如何转换为MyStruct:

if case let .object(data) = feature.properties?["data"] {
  // 这里需要把 data: GEOSwift.JSON 转成 MyStruct
}

GEOSwift.JSON的定义如下:

import Foundation

public enum JSON: Hashable, Sendable {
    case string(String)
    case number(Double)
    case boolean(Bool)
    case array([JSON])
    case object([String: JSON])
    case null

    /// 递归解包并返回关联值
    public var untypedValue: Any {
        switch self {
        case let .string(string):
            return string
        case let .number(number):
            return number
        case let .boolean(boolean):
            return boolean
        case let .array(array):
            return array.map { $0.untypedValue }
        case let .object(object):
            return object.mapValues { $0.untypedValue }
        case .null:
            return NSNull()
        }
    }
}

extension JSON: ExpressibleByStringLiteral {
    public init(stringLiteral value: String) {
        self = .string(value)
    }
}

extension JSON: ExpressibleByIntegerLiteral {
    public init(integerLiteral value: Int) {
        self = .number(Double(value))
    }
}

extension JSON: ExpressibleByFloatLiteral {
    public init(floatLiteral value: Double) {
        self = .number(value)
    }
}

extension JSON: ExpressibleByBooleanLiteral {
    public init(booleanLiteral value: Bool) {
        self = .boolean(value)
    }
}

extension JSON: ExpressibleByArrayLiteral {
    public init(arrayLiteral elements: JSON...) {
        self = .array(elements)
    }
}

extension JSON: ExpressibleByDictionaryLiteral {
    public init(dictionaryLiteral elements: (String, JSON)...) {
        let object = elements.reduce(into: [:]) { (result, element) in
            result[element.0] = element.1
        }
        self = .object(object)
    }
}

extension JSON: ExpressibleByNilLiteral {
    public init(nilLiteral: ()) {
        self = .null
    }
}

解决方案

方法一:通过JSONSerialization转Data后解析

利用JSON枚举的untypedValue属性,先将其转换为Data,再用JSONDecoder解析:

if case let .object(dataJson) = feature.properties?["data"] {
    do {
        // 将JSON对象转成可序列化的Any类型,再生成Data
        let data = try JSONSerialization.data(withJSONObject: dataJson.untypedValue)
        let myStruct = try JSONDecoder().decode(MyStruct.self, from: data)
        // 成功获取MyStruct实例,进行后续处理
    } catch {
        // 处理序列化或解析错误
        print("解析失败:\(error)")
    }
}

方法二:扩展JSON添加通用解析方法

给JSON枚举添加扩展,封装解析逻辑,让调用更简洁:

extension JSON {
    func decode<T: Decodable>(to type: T.Type) throws -> T {
        let data = try JSONSerialization.data(withJSONObject: self.untypedValue)
        return try JSONDecoder().decode(type, from: data)
    }
}

使用时只需:

if case let .object(dataJson) = feature.properties?["data"] {
    do {
        let myStruct = try dataJson.decode(to: MyStruct.self)
        // 使用myStruct
    } catch {
        print("解析错误:\(error)")
    }
}

注意事项

  • 若data字段可能不是.object类型,建议添加额外判断,避免运行时崩溃
  • JSONSerialization.data(withJSONObject:)可能因包含不可序列化类型失败,必须用try捕获错误

内容的提问来源于stack exchange,提问作者benpva16

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 04:12:36