如何在 SwiftUI 中实现 MVVM 模式?视图不会重新渲染

Posted

技术标签:

【中文标题】如何在 SwiftUI 中实现 MVVM 模式?视图不会重新渲染【英文标题】:How to implement the MVVM-Pattern in SwiftUI? The View is not re-rendered 【发布时间】:2020-01-06 12:26:17 【问题描述】:

我正在学习 SwiftUI 并尝试使用 MVVM 模式实现一个简单的 Timer。但是 Timer 的视图不会重新渲染。有什么问题?

// Timer Model

import Foundation

class TimerModel 
    let label: String = "Counter"
    var count: Int = 0

// Timer View Model

import Foundation
import SwiftUI
import Combine

class TimerViewModel: ObservableObject 

    @Published var timerModel: TimerModel = TimerModel()

    var label: String 
        return self.timerModel.label
    

    var count: Int 
        return self.timerModel.count
    

    func startTimer() 
        Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true)  (timer) in

            DispatchQueue.main.async 
                self.timerModel.count += 1
            

        
    

// Timer View 

import SwiftUI
import Combine

struct TimerView: View 

    @ObservedObject var timerViewModel: TimerViewModel

    init() 
        self.timerViewModel = TimerViewModel()
    

    var body: some View 
        VStack 
            Text("\(self.timerViewModel.label): \(self.timerViewModel.count)")
            Button(action: 
                self.timerViewModel.startTimer()
            , label: 
                Text("Start")
            )
        
    


struct TimerView_Previews: PreviewProvider 
    static var previews: some View 
        TimerView()
    

// Content View 

import SwiftUI

struct ContentView: View 

    var body: some View 
        TimerView()
    


struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
        ContentView()
    


Timer View Model 中 Timer Model 的 count 属性每秒钟改变一次,但 Timer View 不会重新渲染。感谢您提供实现 MVVM 模式的任何想法。

【问题讨论】:

【参考方案1】:

最简单的就是把模型改成值类型

struct TimerModel 
    let label: String = "Counter"
    var count: Int = 0

【讨论】:

谢谢你,阿斯佩里。计数器正在运行:)。上面的代码是在大型项目中实现 MVVM 模式的正确方法吗?为什么我需要值类型结构而不是引用类型类? 如果你改变结构的属性,整个结构都会改变,所以@Published wrapper 工作,如果对象(引用类型)的属性改变,对象(实际上是引用)不会改变,所以包装器不发布任何事件。总的来说方法是对的。

以上是关于如何在 SwiftUI 中实现 MVVM 模式?视图不会重新渲染的主要内容,如果未能解决你的问题,请参考以下文章

在 SwiftUI App 中实现暗模式切换

如何在Android MVVM架构中实现对话框选择选项

在 Flutter Native Android 代码中实现 MVVM 架构

如何在 SwiftUI 的视图控制器中实现数据绑定?

如何在 MVVM-C RxSwift 中实现 firebase 身份验证

SwiftUI:如何在 macOS 应用程序中实现编辑菜单