如何将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
相关产品推荐
相关产品推荐

