返回

Swift:API数据传递到视图控制器(含模态窗口)

IOS

将 API 数据传递到用户查询后的视图控制器

在开发过程中,经常需要从 API 获取数据并在视图控制器中展示。本文将讨论如何将用户查询后的 API 数据传递到模态弹出窗口,并以一个航空天气应用为例,详细讲解实现步骤。 这个应用允许用户输入机场代码(例如 KDAB),然后在弹出窗口中显示该机场的实时天气信息。

问题分析

代码示例显示,API 调用成功获取了数据,并能够在控制台打印。 然而,视图控制器中的标签未能正确显示数据。 这是因为数据获取和视图更新之间缺乏正确的连接。 尽管 ReportViewController 实现了 WeatherManagerDelegate 协议,并且 didUpdateWeather 方法能够成功更新 UI,但触发 API 调用的 WxViewController 和显示结果的 ReportViewController 之间没有建立数据传递机制。

解决方案

以下是几种解决方案,可以根据应用架构选择最合适的方案:

1. 使用属性传递数据:

这是最直接的解决方案。在 ReportViewController 中创建一个 weather 属性,用于存储天气数据。 在呈现 ReportViewController 之前,将 API 获取到的 WeatherModel 对象赋值给这个属性。

  • 步骤:

    1. ReportViewController 中添加 weather 属性:

      class ReportViewController: UIViewController, WeatherManagerDelegate {
          var weather: WeatherModel?
      
          // ... 其他代码
      }
      
    2. WxViewController 中的 prepare(for segue:) 方法中设置 weather 属性:

      override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
          if segue.identifier == "showReport" { // 将 "showReport" 替换为你实际的 segue identifier
              let destinationVC = segue.destination as! ReportViewController
              destinationVC.weather = self.weather //  假设 WxViewController 有一个名为 weather 的属性来存储 API 返回的数据
          }
      }
      
    3. ReportViewControllerviewDidLoad() 中使用 weather 属性更新 UI:

      override func viewDidLoad() {
          super.viewDidLoad()
          if let weather = weather {
              flightRulesValueLabel.text = weather.flightRules
              // 更新其他标签
          }
      }
      

      务必将 "showReport" 替换为你实际使用的 segue identifier。
      请注意,WxViewController 需要有一个属性来存储从 didUpdateWeather 方法接收的 weather 数据。修改后的 WxViewController 代码片段如下:

      class WxViewController: UIViewController, UITextFieldDelegate, WeatherManagerDelegate {
      // ...其他代码...
      var weather: WeatherModel?
      
      
          func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel) {
             self.weather = weather
             // 或者直接在此处执行 segue,例如: performSegue(withIdentifier: "showReport", sender: self)
      
          }
      
          // ...其他代码...
      }
      
      
      

2. 使用闭包传递数据:

这种方法更加灵活,可以避免对 segue 的依赖。 在 WxViewController 中定义一个闭包,用于将数据传递给 ReportViewController

  • 步骤:

    1. WxViewController 中定义一个闭包属性:

      class WxViewController: UIViewController {
          var weatherDataHandler: ((WeatherModel) -> Void)?
         // ...其他代码
      }
      
    2. WxViewController 中的 didUpdateWeather 方法中调用闭包:

       func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel) {
              weatherDataHandler?(weather)
          }
      
    3. 在呈现 ReportViewController 之前设置闭包:

     // 假设你使用 present 方法呈现 ReportViewController
     let reportVC = ReportViewController()
     reportVC.modalPresentationStyle = .formSheet //或你想要的样式
    
    weatherDataHandler = { [weak reportVC] weather in
            reportVC?.updateWeatherUI(weather)
    }
     present(reportVC, animated: true)
    
     // 在 ReportViewController 中定义 updateWeatherUI 方法
     func updateWeatherUI(_ weather: WeatherModel){
                flightRulesValueLabel.text = weather.flightRules
    
     }
    
    
    

3. 使用通知传递数据:

这种方法适用于更复杂的场景,例如需要将数据传递给多个视图控制器。

  • 步骤:
    此方法与前两种方法不同,它不依赖于 segue 或直接的视图控制器之间的连接。它利用了 iOS 的通知中心机制,使得一个对象可以广播信息,而其他对象可以监听并接收这些信息,而无需知道彼此的存在。

    1. didUpdateWeather 方法中发送通知:
      func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel) {
          NotificationCenter.default.post(name: .weatherDataUpdated, object: weather)
      }
    
     // 定义一个通知名称,用于区分不同的通知。
        extension Notification.Name {
            static let weatherDataUpdated = Notification.Name("weatherDataUpdated")
        }
    
    1. ReportViewController 中监听通知:
    override func viewDidLoad() {
          super.viewDidLoad()
          NotificationCenter.default.addObserver(self, selector: #selector(updateWeatherUI(_:)), name: .weatherDataUpdated, object: nil)
      }
    
      @objc func updateWeatherUI(_ notification: Notification) {
        if let weather = notification.object as? WeatherModel {
                 flightRulesValueLabel.text = weather.flightRules
               // 更新其他标签
              }
    
    }
    
    
    // 在 deinit 或适当的地方移除观察者
    deinit {
          NotificationCenter.default.removeObserver(self)
      }
    

选择合适的方案取决于你的应用架构和具体需求。 在实际应用中,还应该考虑数据的安全性,例如避免在通知中传递敏感信息。 选择哪种方法取决于具体的应用需求和架构。 属性传递适用于简单的场景,闭包提供更大的灵活性,而通知适用于更复杂的场景。