关于在用户查询后将数据从 API 传递到视图控制器的问题 - Swift

Question about passing data from an API into a view controller after user query - Swift

我正在不知疲倦地开发一个应用程序,但我对 Swift 还是个新手。我试图在用户在登录屏幕上输入后从 API 调用中获取数据,然后在显示用户想要的数据的模态弹出窗口上显示 API 调用的结果。这是一款航空气象应用;用户输入类似“KDAB”的内容和 API returns 该机场当前的航空天气。我为不同的值设置了一堆标签,可以在搜索后将它们打印到控制台,但似乎无法将它们打印在 VC 中。我尝试了一些 destination.segue 修复,但不明白我为什么要使用它们 - 数据直接来自解码 JSON。帮助将不胜感激!

我试图在每个值标签的 ReportViewController 上显示。 IE。使用 .text 属性.

的 windSpeedValueLabel 中的风速

现在,实际 ReportViewController 上的默认标签没有任何变化。

再次感谢。

我的代码:

//
//  ReportViewController.swift
//  AvWx Pro
//
//  Created by Grayson Bertaina on 9/22/20.
//

import UIKit

class ReportViewController: UIViewController, WeatherManagerDelegate {

    var weatherManager = WeatherManager()
    
    @IBOutlet weak var flightRulesTitleLabel: UILabel!
    
    @IBOutlet weak var flightRulesValueLabel: UILabel!
    
    @IBOutlet weak var visibilityValueLabel: UILabel!
    
    @IBOutlet weak var altimeterValueLabel: UILabel!
    
    @IBOutlet weak var cloudsTitleLabel: UILabel!
    
    @IBOutlet weak var cloudsType1Label: UILabel!
    
    @IBOutlet weak var cloudsAltitude1Label: UILabel!
    
    @IBOutlet weak var cloudsType2Label: UILabel!
    
    @IBOutlet weak var cloudsAltitude2Label: UILabel!
    
    @IBOutlet weak var cloudsType3Label: UILabel!
    
    @IBOutlet weak var cloudsAltitude3Label: UILabel!
    
    @IBOutlet weak var windGTextLabel: UILabel!
    
    @IBOutlet weak var windSpeedValueLabel: UILabel!
    
    @IBOutlet weak var windGustValueLabel: UILabel!
    
    @IBOutlet weak var windFromTextLabel: UILabel!
    
    @IBOutlet weak var windDirectionValueLabel: UILabel!
    
    @IBOutlet weak var remarksValueLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Do any additional setup after loading the view.
    }
    

    func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel) {
        DispatchQueue.main.async {
            self.flightRulesValueLabel.text = weather.flightRules
            self.cloudsType1Label.text = weather.lowestCloudsType
        }
        
    }
    
    func didFailWithError(error: Error) {
        print(error)
    }
    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destination.
        // Pass the selected object to the new view controller.
    }
    

}
//
//  ViewController.swift
//  AvWx Pro
//
//  Created by Grayson Bertaina on 9/21/20.
//

import UIKit

class WxViewController: UIViewController, UITextFieldDelegate, WeatherManagerDelegate {

    var weatherManager = WeatherManager()
    
    @IBOutlet weak var stationSearch: UITextField!
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        weatherManager.delegate = self
        stationSearch.delegate = self
    }

    @IBAction func searchPressed(_ sender: Any) {
        print(stationSearch.text!)
        stationSearch.endEditing(true)
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        print(stationSearch.text!)
        stationSearch.endEditing(true)
        return true
    }
    
    func textFieldDidEndEditing(_ textField: UITextField) {
        if let station = stationSearch.text {
            weatherManager.fetchWeather(stationICAO: station)
        }

        stationSearch.text = ""
    }
    
    func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
        if stationSearch.text != "" {
            return true
        } else {
            stationSearch.placeholder = "Type an ICAO"
            return false
        }
    }
    
    func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel) {
        print(weather.flightConditions)
        }
        
    
    
    func didFailWithError(error: Error) {
        print(error)
    }
    
    
  
    
    
}
//
//  WeatherManager.swift
//  AvWx Pro
//
//  Created by Grayson Bertaina on 9/21/20.
//

import Foundation

protocol WeatherManagerDelegate {
    func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel)
    func didFailWithError(error: Error)
}

struct WeatherManager {
    let weatherURL = "https://avwx.rest/api/metar/"
    
    var delegate : WeatherManagerDelegate?

    func fetchWeather (stationICAO: String) {
        let urlString = "\(weatherURL)\(stationICAO)?token=OVi45FiTDo1LmyodShfOfoizNe5m9wyuO6Mkc95AN-c"
        performRequest(with: urlString)
    }
    
    func performRequest (with urlString: String) {
        if let url = URL(string: urlString) {
            let session = URLSession(configuration: .default)
                
            
            let task = session.dataTask(with: url) { (data, response, error) in
                if error != nil {
                    self.delegate?.didFailWithError(error: error!)
                    return
                }
                
                if let safeData = data {
                    if let weather = self.parseJSON(safeData) {
                        self.delegate?.didUpdateWeather(self, weather: weather)
                    }
                }
            }
            
            task.resume()
            print(urlString)
            
            
            }
        }
    
    func parseJSON(_ weatherData: Data) -> WeatherModel? {
        
        
        do {
            let decoder = JSONDecoder()
            let decodedData = try decoder.decode(WeatherData.self, from: weatherData)
            
            
            
            let clouds = decodedData.clouds
            let lowCloudsType = (clouds.count > 0 ? clouds[0]?.type : nil) ?? "N/A"
            let midCloudsType = (clouds.count > 1 ? clouds[1]?.type : nil) ?? "N/A"
            let highCloudsType = (clouds.count > 2 ? clouds[2]?.type : nil) ?? "N/A"
            let lowCloudsAlt = (clouds.count > 0 ? clouds[0]?.altitude : nil) ?? 0
            let midCloudsAlt = (clouds.count > 1 ? clouds[1]?.altitude : nil) ?? 0
            let highCloudsAlt = (clouds.count > 2 ? clouds[2]?.altitude : nil) ?? 0
            let reportingStationVar = decodedData.station ?? "N/A"
            let windGustValue = decodedData.wind_gust?.value ?? 0
            let windSpeedValue = decodedData.wind_speed?.value ?? 0
            let windDirectionValue = decodedData.wind_direction?.value ?? 999
            let visibilityValue = decodedData.visibility?.value ?? 0
            let flightRulesValue = decodedData.flight_rules ?? "N/A"
            
            let weather = WeatherModel(lowestCloudsType: lowCloudsType , lowestCloudsAlt: lowCloudsAlt, middleCloudsType: midCloudsType , middleCloudsAlt: midCloudsAlt, highestCloudsType: highCloudsType , highestCloudsAlt: highCloudsAlt, reportingStation: reportingStationVar, windGust: windGustValue, windSpeed: windSpeedValue, windDirection: windDirectionValue, visibility: visibilityValue, flightRules: flightRulesValue)
            
            return weather
            
        } catch {
            delegate?.didFailWithError(error: error)
            return nil
        }
    }
    
    

}
//
//  WeatherData.swift
//  AvWx Pro
//
//  Created by Grayson Bertaina on 9/21/20.
//

import Foundation

struct WeatherData: Codable {
   
    
    let clouds: [Clouds?]
    let flight_rules: String?
    let remarks: String?
    let wind_speed: WindSpeed?
    let wind_gust: WindGust?
    let wind_direction: WindDirection?
    let visibility: Visibility?

    let station: String?
}



struct Clouds: Codable {
    let type: String
    let altitude: Int
}

struct WindSpeed: Codable {
    let value: Int
}

struct WindGust: Codable {
    let value: Int
}

struct WindDirection: Codable {
    let value: Int
}

struct Visibility: Codable {
    let value: Int
}


再次感谢。

首先,在 WeatherManager 上,将您的委托声明为弱委托以避免引用循环

weak var delegate : WeatherManagerDelegate?

其次,解码数据后,您必须调用委托并传递数据,在本例中,是您刚刚使用委托方法之一创建的 WeatherModel

 do {
            let decoder = JSONDecoder()
            let decodedData = try decoder.decode(WeatherData.self, from: weatherData)
            
            
            
            let clouds = decodedData.clouds
            let lowCloudsType = (clouds.count > 0 ? clouds[0]?.type : nil) ?? "N/A"
            let midCloudsType = (clouds.count > 1 ? clouds[1]?.type : nil) ?? "N/A"
            let highCloudsType = (clouds.count > 2 ? clouds[2]?.type : nil) ?? "N/A"
            let lowCloudsAlt = (clouds.count > 0 ? clouds[0]?.altitude : nil) ?? 0
            let midCloudsAlt = (clouds.count > 1 ? clouds[1]?.altitude : nil) ?? 0
            let highCloudsAlt = (clouds.count > 2 ? clouds[2]?.altitude : nil) ?? 0
            let reportingStationVar = decodedData.station ?? "N/A"
            let windGustValue = decodedData.wind_gust?.value ?? 0
            let windSpeedValue = decodedData.wind_speed?.value ?? 0
            let windDirectionValue = decodedData.wind_direction?.value ?? 999
            let visibilityValue = decodedData.visibility?.value ?? 0
            let flightRulesValue = decodedData.flight_rules ?? "N/A"
            
            let weather = WeatherModel(lowestCloudsType: lowCloudsType , lowestCloudsAlt: lowCloudsAlt, middleCloudsType: midCloudsType , middleCloudsAlt: midCloudsAlt, highestCloudsType: highCloudsType , highestCloudsAlt: highCloudsAlt, reportingStation: reportingStationVar, windGust: windGustValue, windSpeed: windSpeedValue, windDirection: windDirectionValue, visibility: visibilityValue, flightRules: flightRulesValue)
            
            delegate?.didUpdateWeather(self, weather: weather)

            return weather
            
        } catch {
            delegate?.didFailWithError(error: error)
            return nil
        }

在 ReportViewController 上,将自己指定为 viewDidLoad() 上的 WeatherManagerDelegate,然后您必须通过使用相应的值更新标签来实现委托函数 didUpdateWeather——您已经开始了

class ReportViewController: UIViewController, WeatherManagerDelegate {

    var weatherManager = WeatherManager()
    
    @IBOutlet weak var flightRulesTitleLabel: UILabel!
    
    @IBOutlet weak var flightRulesValueLabel: UILabel!
    
    @IBOutlet weak var visibilityValueLabel: UILabel!
    
    @IBOutlet weak var altimeterValueLabel: UILabel!
    
    @IBOutlet weak var cloudsTitleLabel: UILabel!
    
    @IBOutlet weak var cloudsType1Label: UILabel!
    
    @IBOutlet weak var cloudsAltitude1Label: UILabel!
    
    @IBOutlet weak var cloudsType2Label: UILabel!
    
    @IBOutlet weak var cloudsAltitude2Label: UILabel!
    
    @IBOutlet weak var cloudsType3Label: UILabel!
    
    @IBOutlet weak var cloudsAltitude3Label: UILabel!
    
    @IBOutlet weak var windGTextLabel: UILabel!
    
    @IBOutlet weak var windSpeedValueLabel: UILabel!
    
    @IBOutlet weak var windGustValueLabel: UILabel!
    
    @IBOutlet weak var windFromTextLabel: UILabel!
    
    @IBOutlet weak var windDirectionValueLabel: UILabel!
    
    @IBOutlet weak var remarksValueLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        weatherManager.delegate = self
    }
    

    func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel) {
        DispatchQueue.main.async {
            self.flightRulesValueLabel.text = weather.flightRules
            self.cloudsType1Label.text = weather.lowestCloudsType
        }
        
 }