我正在使用MVVM架构来开发一个用于学习的小型天气应用程序。
<<h3>视图/h3>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 {
}
}
}
ViewModel
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通过使用
func getCityDat()
来获取cityId - 在获得
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
有两种不同的方式来连接这些已发布的属性:
- 观察
objectWillChange
,它在任何之前被触发已发布的属性更新 - 独立观察每个@Published属性