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

