首页 > 解决方案 > 如何在 Swift 中连接模型和视图模型的已发布属性?

问题描述

让我们假设一个模型,它实现了协议ObservableObject并且有一个@Published属性name

// MARK: Model
class ContentSinglePropertyModel: ObservableObject {
    @Published public var name: String
}

现在,我想在视图中显示该名称并name在模型发生更改时更新视图。此外,我想使用 Model-View-ViewModel (MVVM) 模式来实现这一目标。

// MARK: ViewModel
final class ContentSinglePropertyViewModel: ObservableObject {
    private let model: ContentSinglePropertyModel

    @Published var name: String = ""

    init() {
        self.model = ContentSinglePropertyModel()
    }
}

// MARK: View
struct ContentSinglePropertyView: View {
    @ObservedObject var viewModel: ContentSinglePropertyViewModel

    var body: some View {
        Text(self.viewModel.name)
    }
}

由于我不喜欢在视图模型中公开模型或其属性的想法,因此一种选择是将模型的属性包装name在视图模型中。我的问题是:如何以name最惯用的方式连接模型和视图模型?

我想出了通过使用 Combine 的assign方法来更新 viewmodel 属性的解决方案:

self.model.$name.assign(to: \.name, on: self).store(in: &self.cancellables)

有更好的解决方案吗?

我的工作示例:

import SwiftUI
import Combine

// MARK: Model
class ContentSinglePropertyModel: ObservableObject {
    @Published public var name: String

    init() {
        self.name = "Initial value"
    }

    func doSomething() {
        self.name = "Changed value"
    }
}

// MARK: ViewModel
final class ContentSinglePropertyViewModel: ObservableObject {
    private let model: ContentSinglePropertyModel
    private var cancellables: Set<AnyCancellable> = []

    @Published var name: String = ""

    init() {
        self.model = ContentSinglePropertyModel()

        // glue Model and ViewModel
        self.model.$name.assign(to: \.name, on: self).store(in: &self.cancellables)
    }

    func doSomething() {
        self.model.doSomething()
    }
}

// MARK: View
struct ContentSinglePropertyView: View {
    @ObservedObject var viewModel: ContentSinglePropertyViewModel

    var body: some View {
        VStack {
            Text(self.viewModel.name)

            Button("Do something!", action: {
                self.viewModel.doSomething()
            })
        }
    }
}

struct ContentSinglePropertyView_Previews: PreviewProvider {
    static var previews: some View {
        ContentSinglePropertyView(viewModel: .init())
    }
}

标签: swiftmvvmswiftuicombine

解决方案


推荐阅读