我创建了这些请求,我不知道我问得是否正确。如果有人能说出来,他们会感激的。这是我的密码。我需要在搜索中搜索一个城市,这样天气就会显示在表格中。请帮助并告诉我如何设置以及在哪里修复它。或者我设置的函数和方法不正确?错误
"数据丢失,无法读取">
import UIKit
class SearchViewController: UIViewController,UISearchResultsUpdating, UITableViewDelegate,UITableViewDataSource {
@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet weak var tableView: UITableView!
var filteredCity: [OpenWeather] = []
// var searchCity: [OpenWeather]=[]
let wetherApi = WeatherManager()
var cityWeather = [OpenWeather]()
let netSer = NetworkService()
let searchController = UISearchController()
var isSearchBarEmpty: Bool {
return searchController.searchBar.text?.isEmpty ?? true
}
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
navigationItem.searchController = searchController
tableView.delegate = self
tableView.dataSource = self
wetherApi.fetchCurrentWeather(city: "London")
}
func updateSearchResults(for searchController: UISearchController) {
self.filteredCity = self.cityWeather.filter { (city:OpenWeather) -> Bool in
if city.city.lowercased().contains(self.searchController.searchBar.text!.lowercased()){
return true
}else {
return false
}
}
//Update the results TableView
self.tableView.reloadData()
}
@objc func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cityWeather.count
}
@objc(tableView:cellForRowAtIndexPath:) internal func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CityTableViewCell
cell.cityTemp.text = cityWeather[indexPath.row].city
cell.cityTemp.text = "(cityWeather[indexPath.row].main.tempCelsius)"
return cell
}
}
我的结构天气:
import Foundation
import UIKit
struct OpenWeather: Codable {
let coord:Coordinate
let city:String
let weathertwo:[WeatherTwo]
let main: Main
}
struct Coordinate: Codable {
let lan:Float
let lot:Float
enum CodingKeys: String, CodingKey {
case lan = "lat"
case lot = "lon"
}
}
struct WeatherTwo: Codable {
let main: String
let description: String
}
struct Main: Codable {
private let temp: Double
var tempCelsius: Double {
get {
return (temp - 32) / 1.8
}
}
private let temp_min: Double
var tempCelsiusmin: Double {
get {
return (temp - 32) / 1.8
}
}
private let temp_max: Double
var tempCelsiusmax: Double {
get {
return (temp - 32) / 1.8
}
}
let pressure: Int
let humidity: Int
}
我的代码Api可编码下载:
struct WeatherManager {
//Deliberately deleted "q=London" within the url, because it needs to be customizable with a different city
func fetchCurrentWeather(city: String){
let URL_API = "https://api.openweathermap.org/data/2.5/weather?q="
let CITY_ID = city
//let URL_API_KEY = "<api_key>"
let session = URLSession(configuration: .default)
let urlString = URL_API + CITY_ID + "&appid=cfe547d810fc4ad95e8f24187c6b08da"
guard let url = URL(string: urlString) else {
print("Error building URL")
return
}
let task = session.dataTask(with: url) { (data, response, error) in
DispatchQueue.main.async {
if let error = error {
print(error.localizedDescription)
return
}
guard let data = data, let response = response as? HTTPURLResponse else {
print("Invalid data or response")
return
}
do {
if response.statusCode == 200 {
let items = try JSONDecoder().decode(OpenWeather.self, from: data)
print(items)
} else {
print("Response wasn't 200. It was: " + "n(response.statusCode)")
}
} catch {
print(error.localizedDescription)
}
}
}
task.resume()
}
}
我看到了发生这种情况的几个原因。
如果你看看API给你的响应,你会发现:
-
键
weathertwo
和city
不存在于响应中,但它们存在于OpenWeather
结构中。如果你不总是期望这些数据出现在中,你需要让它们成为可选的,或者通过重写init来提供默认值 -
查看响应中的
coord
对象
"coord": {
"lon": -0.1257,
"lat": 51.5085
}
将键的拼写与coord结构进行比较:
struct Coordinate: Codable {
let lan:Float
let long:Float
}
如果你想使用不同的变量名,你需要考虑使用CodingKeys
然而,我认为最简单的修复方法是将OpenWeather
结构更改为:
struct OpenWeather: Codable {
let coord: Coordinate
let city: String?
let weathertwo: [WeatherTwo]?
let main: Main
}
并将coords固定为:
struct Coordinate: Codable {
let lat: Float
let lon: Float
}
应该消除错误并给你所需的数据,因为我可以看到控制台上打印的Open Weather API数据:
OpenWeather(coord: TestApp.Coordinate(lat: 25.2582, lon: 55.3047), city: nil, weathertwo: nil, main: TestApp.Main(temp: 300.38, temp_min: 299.31, temp_max: 301.29, pressure: 1008, humidity: 54))
还可以进行其他改进,例如使用CodingKeys对变量使用camel-case,但这是您稍后可以决定的。
试试这个,看看它是否能解决你的问题。
更新
正如你正确指出的,你问如何获得Open Weather支持的城市列表。
我快速看了一下,看起来他们没有API来获得所有城市的列表。他们的API似乎支持您发送城市名称,并将该城市的天气数据发送给您。
然而,他们在这里提供了他们的城市列表
我认为文件history.city.list.json.gz
包含了所有的城市数据,如果你愿意,这些数据可能需要包含在你的应用程序或在线的某个地方。
看一看。