當“getLocation”函式以保存緯度/經度結束時,我想執行“getWeatherInformation”函式
運行下面的代碼,“getWeatherInformation”在“getLocation”函式保存緯度/經度之前啟動。
我認為它會使用“DispatchQueue.main.sync”中的同步同步運行,但事實并非如此。
我該如何解決這個問題?謝謝你。
// get lat/lon of cityName
func getLocation(cityName: String) {
guard let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?q=\(cityName)&appid=\(keyValue)") else {return}
let session = URLSession(configuration: .default)
session.dataTask(with: url) { [weak self] data, response, error in
let successRange = (200..<300)
guard let data = data, error == nil else {return}
let decoder = JSONDecoder()
if let response = response as? HTTPURLResponse, successRange.contains(response.statusCode) {
guard let location = try? decoder.decode(Location.self, from: data) else {return}
DispatchQueue.main.sync {
self?.findLocation(location: location) // save lat&lon
}
} else {
print("error")
}
}.resume()
}
// get weatherInformation using lat/lon
func getWeatherInformation(lat: Double, lon: Double) {
guard let url = URL(string: "https://api.openweathermap.org/data/2.5/onecall?lat=\(lat)&lon=\(lon)&exclude=minutely&appid=\(keyValue)") else {return}
let session = URLSession(configuration: .default)
session.dataTask(with: url) { [weak self] data, response, error in
let successRange = (200..<300)
guard let data = data, error == nil else {return}
let decoder = JSONDecoder()
if let response = response as? HTTPURLResponse, successRange.contains(response.statusCode) {
guard let weatherInformation = try? decoder.decode(WeatherInformation.self, from: data) else {return}
DispatchQueue.main.sync {
self?.configureWeather(weatherInformation: weatherInformation)
self?.hourlyCollectionView.reloadData()
}
} else {
print("error")
}
}.resume()
}
uj5u.com熱心網友回復:
向函式添加完成處理程式引數,getLocation并在資料任務完成時呼叫它。
呼叫時getLocation,傳遞一個閉包而不是依次呼叫getWeatherInformation。
我建議的其他一些改進:
- 移動副作用,例如將位置從方法主體持久化到其完成處理程式。然后它的職責就是獲取一個位置,決議它并將其交給完成處理程式。更可重用。
- 為發出網路請求時可能出現的不同錯誤創建新型別。這將使您能夠更快地發現問題,并根據發生的情況在 UI 中適當地通知用戶。我下面的例子可能有點過于詳細,但希望它能給你一個想法。
- 使用 Swift 的
Result完成處理程式的回傳型別,讓呼叫者知道網路獲取是成功還是失敗。
以下是我建議的寫作方式:
enum LocationFetchError: Error {
case malformedUrl
case networkError(innerError: Error)
case noData
case unexpectedResponse
case parsingError
}
func getLocation(cityName: String, completion: @escaping (Result<Location, Error>) -> Void) {
guard let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?q=\(cityName)&appid=\(keyValue)") else {
completion(.failure(LocationFetchError.malformedUrl))
return
}
let session = URLSession(configuration: .default)
session.dataTask(with: url) { data, response, error in
if let error = error {
completion(.failure(LocationFetchError.networkError(innerError: error)))
return
}
guard let data = data else {
completion(.failure(LocationFetchError.noData))
return
}
let successRange = (200..<300)
guard let response = response as? HTTPURLResponse, successRange.contains(response.statusCode) else {
completion(.failure(LocationFetchError.unexpectedResponse))
return
}
let decoder = JSONDecoder()
guard let location = try? decoder.decode(Location.self, from: data) else {
completion(.failure(LocationFetchError.parsingError))
return
}
completion(.success(location))
}.resume()
}
以下是您如何呼叫此方法:
getLocation(cityName: "Springfield", completion: { [weak self] result in
switch result {
case .success(let location):
DispatchQueue.main.async {
self?.findLocation(location: location)
}
self?.getWeatherInformation(lat: location.lat, lon: location.lon)
case .failure(let error):
print(error.localizedDescription)
// TODO: show alert if needed, don't forget to dispatch to the main queue
}
})
我建議將相同的技術應用于getWeatherInformation. 在這個例子中,我沒有這樣做,但我希望你能明白。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/476586.html
標籤:迅速
上一篇:從字串中獲取特定單詞
