繁体   English   中英

JSONSerialization与URLSession.shared.dataTask错误

[英]JSONSerialization with URLSession.shared.dataTask errors

作为自学Swift的一部分,我正在开发Weather App。 我目前正在尝试整合天气警报。 在序列化从API调用返回的数据之后,我使用名为AlertData的结构来初始化从API调用返回到weather.gov的数据。 或者,至少那是计划。 我已经根据需要从weather.gov请求数据的其他类对我的类进行了建模,但是要获得警报,我需要能够在dataTask中发送变量参数。 我使用来自Apple的Swift应用开发的URL扩展(以下代码),并设置了代码以向用户当前位置发布参数,以获取用户当前所在位置的警报。

当我尝试在我的AlertDataController类(下面的代码)中构造对weather.gov的API调用时,我的问题就来了。 Xcode不断抛出不同的错误,我不确定为什么。 我想使用下面的代码中的保护声明,但是在显示的代码中抛出“无法强制打开非可选类型'[[String:Any]]'”的错误。 当我在展开后将其设为简单的常量分配时,由于扩展名返回可选的URL,因此也会引发相同的错误。

当我直接从guard语句中的字符串构造URL时,相同的代码可以完美地工作:

guard let url = URL(string: (baseURL + locationString + stations)) else {

我想念什么? 抛出我的错误的地方是在dataTask内部,无论它如何到达那里,变量url都是未包装的URL。 提前致谢。

控制器类:

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)"
        var 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

            if let data = data,
                let rawJSON = try? JSONSerialization.jsonObject(with: data),
                let json = rawJSON as? [String: Any],
                let featuresDict = json["features"] as? [[String: Any]],
                let propertiesArray = featuresDict!["properties"] as? [String: Any] {
Error: Cannot force unwrap value of non-optional type '[[String : Any]]'

                let alertData = AlertData(json: propertiesArray)
                completion(alertData)

            } else {
                print("Either no data was returned in AlertDataController.checkWxAlert, or data was not serialized.")

                completion(nil)
                return
            }
        }

        task.resume()
    }

}

网址扩展名:

import Foundation

extension URL {

    func withQueries(_ queries: [String: String]) -> URL? {
        var components = URLComponents(url: self, resolvingAgainstBaseURL: true)
        components?.queryItems = queries.flatMap { URLQueryItem(name: $0.0, value: $0.1) }
        return components?.url
    }

    func withHTTPS() -> URL? {
        var components = URLComponents(url: self, resolvingAgainstBaseURL: true)
        components?.scheme = "https"
        return components?.url
    }
}

错误

无法强制解开非可选类型'[[String:Any]]'的值

很清楚 发生这种情况的原因是,在评估下一个条件时,已经在可选的绑定表达式中将featuresDict展开。

只需删除感叹号

      ... let propertiesArray = featuresDict["properties"] as? [String: Any] {

该错误与URL的创建方式完全无关。

如果featuresDict实际上是一个数组,则不能使用featuresDict["properties"]语法。 带有字符串语法的下标仅适用于字典。 但是您显然有很多字典。

您可以遍历featuresDict数组(为避免混淆,我将其重命名为featuresArray ),可以在完成解包后执行此操作。 或者,如果只希望与每个字典的properties键关联的值组成一个数组,则flatMap可能是一个不错的选择。

例如:

let task = URLSession.shared.dataTask(with: url) { data, _, error in

    guard let data = data,
        error == nil,
        let json = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any],
        let featuresArray = json["features"] as? [[String: Any]] else {
            print("Either no data was returned in AlertDataController.checkWxAlert, or data was not serialized.")

            completion(nil)
            return
    }

    let propertiesArray = featuresArray.flatMap { $0["properties"] }
    let alertData = AlertData(json: propertiesArray)
    completion(alertData)
}

或者,如果AlertData期望这些属性中的每一个本身都是字典,则可以执行以下操作:

let propertiesArray = featuresArray.flatMap { $0["properties"] as? [String: Any] }

只需将其Cast替换为AlertData在其数组json期望的任何类型。

或者,如果您仅对第一个属性感兴趣,则可以使用first而不是flatMap

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM