【发布时间】:2022-02-22 05:24:15
【问题描述】:
我正在尝试 MVVM 我的 SwiftUI 应用程序,但我无法找到一个可行的解决方案将来自 @EnvironmentObject 的共享模型注入应用程序的各种视图的 ViewModels。
下面的简化代码在示例视图的 init() 中创建了一个模型对象,但我觉得我应该在应用程序的顶部创建模型,以便它可以在多个视图之间共享,并将当模型改变时触发重绘。
我的问题是这是否是正确的策略,如果是,如何正确地做,如果不是,我有什么错误,我该如何做。我还没有找到任何例子可以从头到尾真实地证明这一点,我无法判断我是否只是几个属性包装器,或者我完全错误地接近这个。
import SwiftUI
@main
struct DIApp: App {
// This is where it SEEMS I should be creating and sharing Model:
// @StateObject var dataModel = DataModel()
var body: some Scene {
WindowGroup {
ListView()
// .environmentObject(dataModel)
}
}
}
struct Item: Identifiable {
let id: Int
let title: String
}
class DataModel: ObservableObject {
@Published var items = [Item]()
init() {
items.append(Item(id: 1, title: "First Item"))
items.append(Item(id: 2, title: "Second Item"))
items.append(Item(id: 3, title: "Third Item"))
}
func addItem(_ item: Item) {
items.append(item)
print("DM adding \(item.title)")
}
}
struct ListView: View {
// Creating the StateObject here compiles, but it will not work
// in a realistic app with other views that need to share it.
// It should be an app-wide ObservableObject created elsewhere
// and accessible everywhere, right?
@StateObject private var vm: ViewModel
init() {
_vm = StateObject(wrappedValue: ViewModel(dataModel: DataModel()))
}
var body: some View {
NavigationView {
List {
ForEach(vm.items) { item in
Text(item.title)
}
}
.navigationTitle("List")
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(trailing:
Button(action: {
addItem()
}) {
Image(systemName: "plus.circle")
}
)
}
.navigationViewStyle(StackNavigationViewStyle())
}
func addItem() {
vm.addRandomItem()
}
}
extension ListView {
class ViewModel: ObservableObject {
@Published var items: [Item]
let dataModel: DataModel
init(dataModel: DataModel) {
self.dataModel = dataModel
items = dataModel.items
}
func addRandomItem() {
let newID = Int.random(in: 100..<999)
let newItem = Item(id: newID, title: "New Item \(newID)")
// The line below causes Model to be successfully updated --
// dataModel.addItem print statement happens -- but Model change
// is not reflected in View.
dataModel.addItem(newItem)
// The line below causes the View to redraw and reflect additions, but the fact
// that I need it means I am not doing doing this right. It seems like I should
// be making changes to the Model and having them automatically update View.
items.append(newItem)
}
}
}
【问题讨论】:
-
@Asperi 也许,我确实花了很多时间在这两者上,但是在完整的解决方案中使用任何一个都遇到了麻烦。谢谢
标签: mvvm dependency-injection swiftui