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

Swift天气应用开发:URLSession数据解析强制解包报错求助

问题分析与解决方案

首先,你的报错Cannot force unwrap value of non-optional type '[[String : Any]]'根源很明确:你把features解析成了数组类型[[String: Any]](也就是代码里的featuresDict常量),但后续却把它当成字典来使用,还错误地加了强制解包符号!——数组本身不能用字符串键来取值,而且featuresDict本身也不是可选类型,这两个问题叠加导致了报错。

为什么直接字符串拼接URL时没问题?

其实和URL的构建方式无关,大概率是你之前用字符串拼接时的解析逻辑是正确的,后来改URL扩展构建时不小心写错了解析代码,本质问题出在JSON层级的处理上。

修正后的解析逻辑

根据weather.gov API的返回结构,features是一个数组,每个数组元素是包含properties字段的字典(每个元素对应一条天气警报)。你需要先从数组中取出目标元素(比如第一条警报),再提取它的properties。

下面是修正后的checkWxAlert方法代码:

import Foundation
import CoreLocation

struct AlertDataController {
    func checkWxAlert(location: CLLocation, completion: @escaping (AlertData?) -> Void) {
        let baseURL = URL(string: "https://api.weather.gov/alert")!
        let locationString = "\(location.coordinate.latitude),\(location.coordinate.longitude)"
        let query = [
            "active": "1",
            "point": locationString
        ]
        
        guard let url = baseURL.withQueries(query) else {
            completion(nil)
            print("Unable to build URL in AlertDataController.checkWxAlert with supplied queries.")
            return
        }
        
        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            // 先处理错误和数据为空的情况
            guard let data = data, error == nil else {
                print("Error fetching alert data: \(error?.localizedDescription ?? "Unknown error")")
                completion(nil)
                return
            }
            
            do {
                // 使用do-catch替代try?,能捕获序列化具体错误,方便调试
                let rawJSON = try JSONSerialization.jsonObject(with: data)
                guard let json = rawJSON as? [String: Any],
                      let features = json["features"] as? [[String: Any]],
                      // 取第一条警报,若需展示多条可遍历features数组
                      let firstFeature = features.first,
                      let properties = firstFeature["properties"] as? [String: Any] else {
                    print("Failed to parse alert data structure")
                    completion(nil)
                    return
                }
                
                let alertData = AlertData(json: properties)
                completion(alertData)
            } catch {
                print("JSON serialization failed: \(error.localizedDescription)")
                completion(nil)
            }
        }
        task.resume()
    }
}

额外优化建议

  • 用do-catch替代try?:能捕获JSON序列化的具体错误,避免默默失败,调试更高效。
  • 提前处理错误:把error和data为空的判断放在最前面,逻辑更清晰。
  • 避免强制解包:全程用guard let安全解析JSON层级,降低崩溃风险。
  • 支持多条警报:如果需要展示所有活跃警报,可以遍历features数组,将每个元素的properties转换为AlertData,同时把completion的类型调整为([AlertData]?) -> Void。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:38:10