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

Swift解析JSON获取formatted_address时崩溃,寻求解决方案

解决Swift解析JSON时results字段类型不匹配的崩溃问题

我来帮你搞定这个问题!你的崩溃原因很明确:你把JSON里的results数组错误地强制转换成了字典类型[String:Any],而实际上results是一个包含字典元素的数组(哪怕只有一个元素,它的类型依然是数组,也就是你看到的__NSSingleObjectArrayI——这是OC底层的单元素数组类型,对应Swift里的Array)。

问题分析

你初始代码打印的JSON里,results是一个数组结构,比如类似这样的格式:

{
  "results": [
    {
      "formatted_address": "xxx",
      "address_components": [...]
    }
  ]
}

所以json["results"]的真实类型是[[String:Any]](字典数组),而你用as! [String:Any]强行转成单个字典,类型不匹配,自然会触发运行时崩溃。

修正后的代码(安全解析版)

我们用可选绑定替代强制解包,既避免崩溃,又能正确获取目标字段:

func loadUrl(url: String) {
    DispatchQueue.global().async {
        do {
            // 先检查URL是否有效,避免强制解包URL的崩溃
            guard let appUrl = URL(string: url) else {
                DispatchQueue.main.async {
                    print("无效的URL地址")
                }
                return
            }
            
            let data = try Data(contentsOf: appUrl)
            let json = try JSONSerialization.jsonObject(with: data) as! [String: Any]
            
            // 正确将results解析为字典数组
            if let results = json["results"] as? [[String: Any]] {
                // 取出数组中的第一个结果(如果数组非空)
                if let firstResult = results.first {
                    // 获取formatted_address字段
                    if let formattedAddress = firstResult["formatted_address"] as? String {
                        DispatchQueue.main.async {
                            print("格式化地址:\(formattedAddress)")
                        }
                    }
                    
                    // 获取address_components字段(它本身也是一个数组)
                    if let addressComponents = firstResult["address_components"] as? [[String: Any]] {
                        DispatchQueue.main.async {
                            print("地址组件:\(addressComponents)")
                        }
                    }
                } else {
                    DispatchQueue.main.async {
                        print("results数组为空")
                    }
                }
            } else {
                DispatchQueue.main.async {
                    print("无法解析results字段")
                }
            }
            
        } catch {
            DispatchQueue.main.async {
                print("请求或解析错误:\(error.localizedDescription)")
            }
        }
    }
}

更优雅的方案:使用Codable协议

如果你的项目经常需要解析JSON,强烈推荐使用Swift的Codable协议,它比JSONSerialization更类型安全,代码也更简洁,能从根源上避免类型转换错误:

首先定义对应JSON结构的模型:

// 地址组件模型
struct AddressComponent: Codable {
    let long_name: String
    let short_name: String
    let types: [String]
}

// 单个地址结果模型
struct AddressResult: Codable {
    let formatted_address: String
    let address_components: [AddressComponent]
}

// 整体响应模型
struct GeocodeResponse: Codable {
    let results: [AddressResult]
}

然后用JSONDecoder解码:

func loadUrlWithCodable(url: String) {
    DispatchQueue.global().async {
        do {
            guard let appUrl = URL(string: url) else {
                DispatchQueue.main.async {
                    print("无效的URL地址")
                }
                return
            }
            
            let data = try Data(contentsOf: appUrl)
            // 直接解码为模型对象,编译器会帮我们检查类型
            let response = try JSONDecoder().decode(GeocodeResponse.self, from: data)
            
            if let firstResult = response.results.first {
                DispatchQueue.main.async {
                    print("格式化地址:\(firstResult.formatted_address)")
                    print("地址组件:\(firstResult.address_components)")
                }
            } else {
                DispatchQueue.main.async {
                    print("没有找到地址结果")
                }
            }
            
        } catch {
            DispatchQueue.main.async {
                print("请求或解析错误:\(error.localizedDescription)")
            }
        }
    }
}

这种方式不需要手动做类型转换,编译器会在编译阶段检查字段是否匹配,大大降低运行时崩溃的概率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:46:00