swift - 使用 MVVM 架构快速更新数据
问题描述
我正在使用 MVVM 架构来学习开发用于学习目的的小型天气应用程序。
看法
class ViewController: UIViewController {
private var cityDataViewModel = CityDataViewModel()
private var data = [ConsolidatedWeather]()
@IBOutlet weak var label1: UILabel!
@IBOutlet weak var label2: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
loadCityData()
}
func loadCityData(){
print("loadCityData")
cityDataViewModel.getCityData {
}
}
}
视图模型
class CityDataViewModel{
private var networkManager = CityNetworkManager()
private var weatherNetworkManager = WeatherNetworkManager()
var weatherModel = [ConsolidatedWeather]()
var myStruct :[WeatherModel] = []
var weatherState: String?
var minTemp: Double?
var maxTemp: Double?
var currentTemperature: Double?
var summary: String?
var dateString: String = ""
//MARK: - Get cityInformation
func getCityData(completion: @escaping () -> ()) {
networkManager.getCityDataNetworkCall { [weak self](result) in
switch result{
case .success(let information):
information.forEach { (data) in
print("\(data.title) || \(data.locationType) || \(data.woeid) || \(data.lattLong)")
print("loadCityData 3")
self?.getCityWeatherInformation(with: data.woeid)
print("loadCityData 4")
}
completion()
case .failure(let error):
print(error)
}
}
}
//MARK: - Get Weather data
func getCityWeatherInformation(with woeid: Int){
//[weak self]
weatherNetworkManager.getWeatherDataNetworkCall(cityId: woeid) {[weak self] (result) in
print("loadCityData 5")
switch result{
case .success(let listOfData):
self?.weatherModel = listOfData.consolidatedWeather
}
case .failure(let error):
print(error)
}
}
}
var ttile: String{
return weatherState ?? ""
}
}
- 从视图中,我正在向 ViewModel 发送调用以通过使用获取 cityId
func getCityDat()
- 得到后,
cityId
我要求func getCityWeatherInformation(with woeid: Int)
获取详细的天气数据。我成功地从服务器获取这些数据。
我怎样才能将该信息发送到view
更新我的viewController
?
解决方案
如评论中提到的那样设置协议/闭包系统当然是一个流行的选择。
从 iOS 13 开始,您还可以选择使用 Combine 来发布您的更改ViewModel
,这可以触发ViewController
更新。
一个简化的例子:
import Combine
import UIKit
class MyVC : UIViewController {
private var label = UILabel()
private var label2 = UILabel()
private var viewModel = ViewModel()
private var cancellables = Set<AnyCancellable>()
override func viewDidLoad() {
addLabels()
linkPublishers()
viewModel.getData()
}
func linkPublishers() {
//OPTION 1
viewModel.objectWillChange.sink { (_) in
DispatchQueue.main.async {
self.label.text = self.viewModel.text1
self.label2.text = self.viewModel.text2
}
}
.store(in: &cancellables)
// **** OR ****
//OPTION 2
viewModel
.$text1
.receive(on: RunLoop.main)
.sink { (newLabelText) in
self.label.text = newLabelText
}.store(in: &cancellables)
viewModel
.$text2
.receive(on: RunLoop.main)
.sink { (newLabelText) in
self.label2.text = newLabelText
}.store(in: &cancellables)
}
func addLabels() {
label.frame = CGRect(x: 0, y: 0, width: 200, height: 40)
self.view.addSubview(label)
label2.frame = CGRect(x: 0, y: 40, width: 200, height: 40)
self.view.addSubview(label2)
}
}
class ViewModel : ObservableObject {
@Published var text1 = ""
@Published var text2 = ""
func getData() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.text1 = "Hello, world"
}
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.text2 = "Hello, world 2"
}
}
}
这里做了一个模拟ViewModel
异步网络调用的假任务。然后,它将其@Published 属性之一设置为该数据的结果。
回到ViewController
,linkPublishers
有两种不同的方式来连接这些已发布的属性:
- Observing
objectWillChange
,在任何已发布的属性更新之前触发 - 独立观察每个 @Published 属性。
推荐阅读
- java - InnoSetup 编译器设置文件不创建数据库文件
- python - python - 具有不同键的 Json 数据
- python - 如何让凯撒密码在保留案例的同时忽略空格和标点符号?
- angular - 我如何更改默认文本“按 Enter 键添加”标签输入表单中的角度?
- join - SAS多对多合并
- python - 无法使用 DearPyGui 为绘制的图形添加单击处理程序
- javascript - 将状态/数据传递给功能组件,我做错了/更容易吗?
- firebase - 连接到 firebaseio.com 需要什么证书?
- r - 使用数据集在 R 中创建直方图
- python - 在 RTX 3070 问题上使用 Tensorflow 1.5.0 训练 ResNet50