我具有由键盘输入触发的功能,如果输入正确,则应用程序可以正确进行;如果不是,则该应用程序实际上死机并且无法更改键盘输入(需要重新启动)。
这就是所谓的函数:
override func viewDidLoad() {
super.viewDidLoad()
makeGetCall()
repeat{
RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.1))
}while !done
正在调用的函数:
func makeGetCall() {
let jsonUrlString = "http://api.openweathermap.org/data/2.5/weather?q=" + city + ",us&appid=f0d10597634568abee813f68138452fd&units=imperial"
guard let url = URL(string: jsonUrlString) else {
print("Error: cannot create URL")
return
}
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else {
print("Error: did not receive data")
return
}
do {
self.document = try JSONDecoder().decode(WeatherDocument.self, from: data)
self.done = true
print(self.document!)
print("========================INIT===============================")
print(self.document?.main?.temp! ?? "No temp")
print(self.document?.name! ?? "No temp")
print(self.document?.weather![0].description ?? "No info")
print(self.document?.wind?.speed ?? "No wind")
print("==========================END===============================")
print(self.document?.weather![0].main ?? "No main info")
} catch let jsonErr {
print("Error serializing json:", jsonErr)
}
}.resume()
}
为什么会这样?
这是控制台中显示的错误消息:
“序列化json时出错:typeMismatch(Swift.Double,Swift.DecodingError.Context(codingPath:[CodingKeys(stringValue:” cod“,intValue:nil)]],debugDescription:”预期对Double进行解码,但找到了字符串/数据相反。“,underlyingError:nil)”
天气文档
struct WeatherDocument: Decodable {
let coord: Coordinates?
let weather: [Weather]?
let base: String?
let main: Main?
let visibility: Double?
let wind: Wind?
let clouds: Clouds?
let dt: Double?
let sys: Sys?
let id: Double?
let name: String?
let cod: Double?
}
现在,应用程序在我所做的以下声明中执行断点操作:
let tempe = (self.document?.main?.temp!)!
let humiditye = (self.document?.main?.humidity!)!
let pressurePow = (self.document?.main?.pressure!)! * 0.295300 * 0.10
let tempeMax = (self.document?.main?.temp_max!)! - 273.15
let tempeMin = (self.document?.main?.temp_min!)! - 273.15
//let clouding = (self.precip?.threeHours!)!
let name = (self.document?.name!)!
为什么完成处理程序对此有问题?
答案 0 :(得分:1)
两个问题:
该错误明确指出cod
的类型为String。您可以将所有结构成员声明为非可选。 Openweathermap发送可靠的数据。仅有少数几个可选值(例如,预测API中的Rain
)
let cod : String
从不使用此类重复循环。您阻塞线程。使用完成处理程序。强烈建议使用URLComponents
,它会隐式添加百分比编码。
var city = "New York,us"
let apiKey = <your api key>
...
func makeGetCall(completion: @escaping (WeatherDocument?, Error?)->Void) {
var urlComponents = URLComponents(string: "https://api.openweathermap.org/data/2.5/weather")!
let queryItems = [URLQueryItem(name: "q", value: city),
URLQueryItem(name: "appid", value: apiKey),
URLQueryItem(name: "units", value: "imperial")]
guard let url = urlComponents.url else {
print("Error: cannot create URL")
return
}
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else {
print("Error: did not receive data")
completion(nil, error!)
}
do {
let document = try JSONDecoder().decode(WeatherDocument.self, from: data)
print(document)
print("========================INIT===============================")
print(document.main.temp) // main and temp can be non-optional
print(document.name) // name can be non-optional
print(document.weather[0].description) // weather and description can be non-optional
print(document.wind.speed) // wind and speed can be non-optional
print("==========================END===============================")
print(document.weather[0].main) // weather and main can be non-optional
completion(document, nil)
} catch {
print("Error serializing json:", error)
completion(nil, error)
}
}.resume()
}
并调用它
makeGetCall() { doc, error in
if let doc = doc {
self.document = doc
} else {
print(error!)
}
}
PS:您正在混合天气预报和天气 API。您的结构属于天气预报API,其中cod
实际上是Int
–但是代码(和解码错误)属于weather API。问题中的结构永远无法与此代码/网址一起使用。
答案 1 :(得分:0)
问题是这样的:
makeGetCall()
repeat{
RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.1))
} while !done
您只拨打一次makeGetCall()
。如果失败,您将永远重复RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.1))
调用,从而阻塞了主线程。如果要重新尝试makeGetCall
直到它起作用,请将其向下移动到repeat
块中。
听起来好像还有一个解码问题会阻止makeGetCall()
完成,但我将其留给另一个答案。