Давайте предположим модель, которая реализует протокол 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)
}
}
Поскольку мне не нравится идея сделать модель или ее свойства опубликованными c в пределах модели представления, один из вариантов - заключить свойство модели name
в модель представления. У меня вопрос : Как связать name
модели и модели представления наиболее идиоматическим способом c?
Я нашел решение обновить модель представления свойство с помощью метода присвоения в Combine:
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())
}
}