Swift解码特殊结构JSON(Photon地理API)失败,无法提取坐标与国家代码
现有代码核心错误定位
- 根解码类型不匹配:接口返回的是包含
features字段的单个JSON对象,并非数组,原代码使用[features].self作为根解码类型,从起点就无法匹配结构 - 字段类型匹配错误:
Features结构中错误将geometry、properties声明为数组类型[Geometry]、[Properties],但实际JSON中这两个字段都是单个嵌套对象,不属于数组结构 - 异常处理缺失:全程使用
try?吞掉所有网络、解码错误,无法定位具体的结构不匹配问题 - 编码习惯问题:结构体命名小写开头,不符合Swift的类型命名规范
- 网络请求方式问题:使用同步的
Data(contentsOf:)获取数据,会阻塞当前线程,生产环境会造成UI卡顿
修正后的可运行实现
首先是匹配JSON结构的精简Codable模型,仅声明需要提取的字段即可,未声明的JSON字段会被自动忽略:
import Foundation // 对应返回值的根JSON对象 struct PhotonResponse: Codable { let features: [Feature] } // 对应features数组中的单个对象 struct Feature: Codable { let geometry: Geometry let properties: Properties } // 对应geometry嵌套对象,存储坐标信息 struct Geometry: Codable { let coordinates: [Double] } // 对应properties嵌套对象,仅保留需要提取的国家代码字段 struct Properties: Codable { let countrycode: String }
然后是修正后的解码逻辑,替换掉吞异常的写法,加入错误日志方便后续调试:
var parsedFeatures: [Feature] = [] let targetURLString = "https://photon.komoot.io/api/?q=Greece" guard let targetURL = URL(string: targetURLString) else { return } do { let data = try Data(contentsOf: targetURL) let decoder = JSONDecoder() // 根层级解码为单个响应对象,而非数组 let response = try decoder.decode(PhotonResponse.self, from: data) parsedFeatures = response.features // 提取目标字段示例 for item in parsedFeatures { let coordinateLon = item.geometry.coordinates[0] let coordinateLat = item.geometry.coordinates[1] let code = item.properties.countrycode print("提取结果:经度\(coordinateLon),纬度\(coordinateLat),国家代码\(code)") } } catch { // 直接打印具体错误,避免盲调试 print("运行失败:\(error.localizedDescription)") }
开发注意事项
- 编写Codable模型时,属性的层级、类型必须和JSON结构严格对齐,不要凭主观直觉判断字段是对象还是数组
- 不需要提取的JSON字段无需全部写入模型,Codable会自动忽略未声明的内容,精简模型可以减少维护成本
- 调试JSON解码问题时,禁止过度使用
try?吞掉所有异常,打印具体的DecodingError可以快速定位到不匹配的字段 - 实际生产场景请将同步网络请求替换为URLSession异步请求,避免阻塞主线程
内容的提问来源于stack exchange,提问作者Márcio Silva
相关产品推荐
相关产品推荐

