Swift:API数据传递到视图控制器(含模态窗口)
2024-11-07 04:09:12
将 API 数据传递到用户查询后的视图控制器
在开发过程中,经常需要从 API 获取数据并在视图控制器中展示。本文将讨论如何将用户查询后的 API 数据传递到模态弹出窗口,并以一个航空天气应用为例,详细讲解实现步骤。 这个应用允许用户输入机场代码(例如 KDAB),然后在弹出窗口中显示该机场的实时天气信息。
问题分析
代码示例显示,API 调用成功获取了数据,并能够在控制台打印。 然而,视图控制器中的标签未能正确显示数据。 这是因为数据获取和视图更新之间缺乏正确的连接。 尽管 ReportViewController
实现了 WeatherManagerDelegate
协议,并且 didUpdateWeather
方法能够成功更新 UI,但触发 API 调用的 WxViewController
和显示结果的 ReportViewController
之间没有建立数据传递机制。
解决方案
以下是几种解决方案,可以根据应用架构选择最合适的方案:
1. 使用属性传递数据:
这是最直接的解决方案。在 ReportViewController
中创建一个 weather
属性,用于存储天气数据。 在呈现 ReportViewController
之前,将 API 获取到的 WeatherModel
对象赋值给这个属性。
-
步骤:
-
在
ReportViewController
中添加weather
属性:class ReportViewController: UIViewController, WeatherManagerDelegate { var weather: WeatherModel? // ... 其他代码 }
-
在
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 返回的数据 } }
-
在
ReportViewController
的viewDidLoad()
中使用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
。
-
步骤:
-
在
WxViewController
中定义一个闭包属性:class WxViewController: UIViewController { var weatherDataHandler: ((WeatherModel) -> Void)? // ...其他代码 }
-
在
WxViewController
中的didUpdateWeather
方法中调用闭包:func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel) { weatherDataHandler?(weather) }
-
在呈现
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 的通知中心机制,使得一个对象可以广播信息,而其他对象可以监听并接收这些信息,而无需知道彼此的存在。- 在
didUpdateWeather
方法中发送通知:
func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel) { NotificationCenter.default.post(name: .weatherDataUpdated, object: weather) } // 定义一个通知名称,用于区分不同的通知。 extension Notification.Name { static let weatherDataUpdated = Notification.Name("weatherDataUpdated") }
- 在
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) }
- 在
选择合适的方案取决于你的应用架构和具体需求。 在实际应用中,还应该考虑数据的安全性,例如避免在通知中传递敏感信息。 选择哪种方法取决于具体的应用需求和架构。 属性传递适用于简单的场景,闭包提供更大的灵活性,而通知适用于更复杂的场景。