【问题标题】:Can't access JSON data from Weather API无法从 Weather API 访问 JSON 数据
【发布时间】:2020-04-27 11:00:59
【问题描述】:
class WeatherData {
    private let urlSession = URLSession.shared
    private let urlPathBase = "https://api.worldweatheronline.com/premium/v1/weather.ashx?key=efcc8b6300354517b08194421202604&format=json&q="

    private var dataTask:URLSessionDataTask? = nil

    var delegate:WeatherDataProtocol? = nil

    init(){}

    func getData(exampleDataNumber: String){

        var urlPath = self.urlPathBase
        urlPath = urlPath + exampleDataNumber

        let url:NSURL? = NSURL(string: urlPath)
        print(url!)

        let dataTask = self.urlSession.dataTask(with: url! as URL) {(data, response, error) -> Void in
            if error != nil {
                print(error!)
            } else {
                do {
                    let jsonResult = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary
                    if jsonResult != nil {
                        print(jsonResult)
                        let temperature_c = jsonResult?.value(forKeyPath: "data.current_condition.temp_C") as Any

                        if temperature_c != nil {
                            self.delegate?.responseDataHandler(data: jsonResult!)
                        } else {
                            self.delegate?.responseError(message: "Fake data not found")
                        }
                    } else {
                        print("Fake data")
                    }
                } catch {
                    print("Error")
                }
            }
        }

    }





}

我有上面的代码来访问 worldweatheronline API。在视图控制器中,我将用户输入到城市和州字段的值作为 exampleDataNumber 传递给 getData,它们之间用逗号隔开,空格用 + 删除(因此,奥斯汀,德克萨斯或旧金山,加利福尼亚)。这是基于我的教授为我们提供的一个单独示例的代码,该示例有效,但出于某种原因,此代码将打印 url,但我输入的所有其他打印语句都可以尝试查看通过所有的数据并没有打印任何东西,这真的让我感到困惑,因为似乎应该打印一些东西。我确实知道 API 响应的是 HTTP 而不是 HTTPS,但我在 Info.plist 的 App Transport Security Settings 中添加了允许不安全的HTTPLoads(尝试了 worldweatheronline.net 和 worldweatheronline.com)。还有什么我想念的吗?

【问题讨论】:

  • 请记住,也不要强行打开您的值 - 您的应用程序是否因此而崩溃?另外,如果您在dataTask 之后打印数据,会返回什么? JSON?
  • 应用程序没有崩溃,它只是打印了 url,就是这样
  • 这是我打印 dataTask 时打印的内容:LocalDataTask .
  • 如果这是您对 Data 的响应,同样是 jsonResult - 需要进一步检查链

标签: swift api


【解决方案1】:

代码很好,我想你只是错过了为数据任务调用resume 方法。此外,正如您所说,由于 API 使用 https,因此不需要 ATS 异常。当您在末尾定义let datatask = ... 时,只需添加.resume() 即可立即开始任务。

像这样:

  class WeatherData {
     private let urlSession = URLSession.shared
     private let urlPathBase = "https://api.worldweatheronline.com/premium/v1/weather.ashx?key=efcc8b6300354517b08194421202604&format=json&q="

     private var dataTask:URLSessionDataTask? = nil

     var delegate:WeatherDataProtocol? = nil

     init() {
     }

     func getData(exampleDataNumber: String){

        var urlPath = self.urlPathBase
        urlPath = urlPath + exampleDataNumber

        let url:NSURL? = NSURL(string: urlPath)
        print(url!)

        let dataTask = self.urlSession.dataTask(with: url! as URL) {(data, response, error) -> Void in
           if error != nil {
              print(error!)
           } else {
              do {
                 let jsonResult = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary
                 if jsonResult != nil {
                    print(jsonResult)
                    let temperature_c = jsonResult?.value(forKeyPath: "data.current_condition.temp_C") as Any

                    if temperature_c != nil {
                       self.delegate?.responseDataHandler(data: jsonResult!)
                    } else {
                       self.delegate?.responseError(message: "Fake data not found")
                    }
                 } else {
                    print("Fake data")
                 }
              } catch {
                 print("Error")
              }
           }
        }.resume()
     }
  }

我创建了一个小项目来测试它,看起来不错:

如果您想玩示例项目,可以从以下地址下载:https://github.com/acyrman/StackOverflow61449278

我必须创建和实现WeatherDataProtocol,因为你没有分享那个代码我创建了一个非常简单的代码来编译项目。

【讨论】:

  • 现在最好使用强类型并利用 JSON 解码器。您可以使用像 app.quicktype.io 这样的网站来生成代表 json 响应的 Swift 数据结构代码。使用您项目中的代码,您可以像这样解码数据:let weatherInfo = try JSONDecoder().decode(WeatherDataStructure.self, from: data)
【解决方案2】:

从函数中dataTask 的声明中删除let。您需要设置 ivar,使其在 URLSession 执行时具有强引用。

【讨论】:

  • 我将 let 更改为 var 并没有改变任何东西。这就是你要我做的吗?
  • URLSessionDataTask 在没有强参考的情况下也能正常工作。
猜你喜欢
  • 2017-08-18
  • 1970-01-01
  • 1970-01-01
  • 2016-11-04
  • 2021-06-20
  • 2017-11-03
  • 2017-12-08
  • 1970-01-01
相关资源
最近更新 更多