簡體   English   中英

由於程序未按順序執行的Swift方法不等待URLSession.shared.dataTask完成

[英]Swift Methods Executing Out of Order as Program is Not Waiting for URLSession.shared.dataTask to Finish

我正在嘗試編寫一個應用程序,其中從API檢索數據並隨后顯示在應用程序視圖中。 問題是,當我運行代碼時,即使在getJson()函數之后調用它,在其中獲取視圖的setupViews()始終在檢索JSON數據之前運行。 getJson()函數先運行,但在“ URLSession.shared.dataTask(with:the_urlObj){(data,_,error)in”處停止,然后跳過該函數的其余部分,然后執行所有其余的在程序返回之前先運行。 在調用setupViews()函數之前,如何獲取完整的getJson()函數來執行?

我注意到,URLSession.shared.dataTask行是getJson()函數中的代碼停止的位置。 在setupViews()函數已經執行之后,它將返回到該代碼的其余部分。 我嘗試在URLSession.shared.dataTask行之后的getJson()塊中調用self.setupViews(),但是視圖仍然顯示而沒有數據。

// viewDidLoad函數

override func viewDidLoad() {
    super.viewDidLoad()
    getJson()
    setupViews()
}

// getJson函數

func getJson(){
    let jsonString = "https://api.openweathermap.org/data/2.5/weather?q=brooklyn,us&APPID=f942c97cab0e663a9a4882e6c3f0db1e"
    guard let url = URL(string: jsonString) else { return }
    URLSession.shared.dataTask(with: url) { (data,response,err) in
        guard let data = data else { return }
    do {

        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase
        decoder.dateDecodingStrategy = .secondsSince1970
        let weatherData = try decoder.decode(WeatherData.self, from: data)
        print("temperature: ", weatherData.main.temp)
        // self.todays_weather.text = String("\(temperature)")
        temperature = Int(weatherData.main.temp)
        temperature = (temperature * 9/5)-459

    }
    catch {
        print(err)
        print(response)
    }

}.resume()

}

//設置視圖功能

func setupViews(){
    self.view.addSubview(todays_weather)
    todays_weather.heightAnchor.constraint(equalToConstant: 140).isActive = true
    todays_weather.widthAnchor.constraint(equalToConstant: 150).isActive = true
    todays_weather.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
    todays_weather.centerYAnchor.constraint(equalTo: self.view.topAnchor, constant: 120).isActive = true

    self.view.addSubview(weather_button)
    weather_button.heightAnchor.constraint(equalToConstant: 240).isActive = true
    weather_button.widthAnchor.constraint(equalToConstant: 300).isActive = true
    weather_button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
    weather_button.centerYAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -90).isActive = true

}

let todays_weather : UITextField = {
    let weather = UITextField()
    weather.textColor = UIColor.black
    weather.textAlignment = .center
    weather.text = String("\(temperature)")
    weather.font = UIFont.systemFont(ofSize:32)
    weather.translatesAutoresizingMaskIntoConstraints = false
    return weather
}()

代碼運行良好,但是視圖中的文本字段顯示為0而不是JSON檢索的溫度,因為由於getJson()函數在URLSession.shared處停止,因此setupViews()在JSON數據檢索完成之前就已執行。 dataTask。

我在控制台中收到此通知:2019-07-29 11:44:01.060026-0400 daily_tips [46459:8017625]從主線程訪問引擎后,此應用程序正在從后台線程修改AutoLayout引擎。 這會導致引擎損壞和奇怪的崩潰。

任何幫助,將不勝感激,謝謝!

歡迎來到StackOverflow! 對您來說,JSON提取是異步發生的,但是您在調用setupViews()之后立即調用getJson()

一個好的解決方案是在getJson()調用中添加一個完成處理程序。

func getJson(completionHandler: () -> ()){
    let jsonString = "https://api.openweathermap.org/data/2.5/weather?q=brooklyn,us&APPID=f942c97cab0e663a9a4882e6c3f0db1e"
    guard let url = URL(string: jsonString) else { return }
    URLSession.shared.dataTask(with: url) { (data,response,err) in
        guard let data = data else { return }
        do {

            let decoder = JSONDecoder()
            decoder.keyDecodingStrategy = .convertFromSnakeCase
            decoder.dateDecodingStrategy = .secondsSince1970
            let weatherData = try decoder.decode(WeatherData.self, from: data)
            print("temperature: ", weatherData.main.temp)
            // self.todays_weather.text = String("\(temperature)")
            temperature = Int(weatherData.main.temp)
            temperature = (temperature * 9/5)-459
            completionHandler()
        }
        catch {
            print(err)
            print(response)
        }

    }.resume()
}

然后在completionHandler中調用setupViews():

override func viewDidLoad() {
    super.viewDidLoad()
    getJson { [weak self] in
        DispatchQueue.main.async {
            self?.setupViews()
        }
    }
} 

我建議搜索“ ios異步編程”和“ ios完成處理程序”以了解更多信息。 有很多很棒的信息,希望對您有所幫助。

沒有完成處理簡單的解決方案,把setupViews()在完成處理dataTask

在openweathermap URL中使用參數units=imperial ,您將獲得所有華氏度。

override func viewDidLoad() {
    super.viewDidLoad()
    getJson()
}

func getJson(){
    let jsonString = "https://api.openweathermap.org/data/2.5/weather?q=brooklyn,us&units=imperial&APPID=f942c97cab0e663a9a4882e6c3f0db1e"
    guard let url = URL(string: jsonString) else { return }
    URLSession.shared.dataTask(with: url) { [unowned self] data, response, error in
        guard let data = data else { print(error!); return }
    do {

        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase
        decoder.dateDecodingStrategy = .secondsSince1970
        let weatherData = try decoder.decode(WeatherData.self, from: data)
        print("temperature: ", weatherData.main.temp)
        // self.todays_weather.text = String("\(temperature)")
        temperature = Int(weatherData.main.temp)
        DispatchQueue.main.async {
            self.setupViews()
        }

    }
    catch {
        print(error)
        print(response)
    }

}.resume()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM