首页 > 解决方案 > 使用 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 ?? ""
    }   
}

我怎样才能将该信息发送到view更新我的viewController

标签: swiftmvvm

解决方案


如评论中提到的那样设置协议/闭包系统当然是一个流行的选择。

从 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有两种不同的方式来连接这些已发布的属性:

  1. Observing objectWillChange,在任何已发布的属性更新之前触发
  2. 独立观察每个 @Published 属性。

推荐阅读