看来我完全失去了 MVVM 数据流的概念: 我有一个简单的示例视图,显示 Doc 项目数组,由 ViewModel 类提供,该类必须是单例,可以从多个位置访问。 每个项目都有名称和一个按钮,应该更改它的“isFav”值,并通过所述按钮的颜色变化反映变化。
我尝试通过 vm 函数、struct mutating func 等直接方式来更改它,但我提出的每一个都会给我带来不同的错误。 我做错了什么?
import SwiftUI
struct Doc: Identifiable
{
let id: UUID
var name: String
var isFav: Bool = false
init(_ name: String)
{
self.id = UUID()
self.name = name
}
init()
{
self.id = UUID()
self.name = id.uuidString.dropLast(13).lowercased()
}
mutating func updateIsFav()
{
self.isFav.toggle()
}
}
class ViewModel: ObservableObject
{
static var shared = ViewModel()
private init() {}
@Published var array: [Doc] = []
func updateIsFav(for doc: Doc)
{
if let index = array.firstIndex(where: { $0.id == doc.id} )
{
self.array[index].isFav.toggle()
}
}
}
struct ContentView: View
{
@ObservedObject var model = ViewModel.shared
var body: some View
{
ZStack
{
Color.black.ignoresSafeArea()
ScrollView
{
VStack
{
ForEach( model.array, id: \.id )
{
doc in
HStack
{
Text( doc.name )
.foregroundColor(.white)
Button(action:
{
doc.updateIsFav() // Cannot use mutating member on immutable value: 'doc' is a 'let' constant
doc.isFav.toggle // Cannot reference 'mutating' method as function value
model.updateisFav(for: doc) // Cannot call value of non-function type 'Binding<Subject>'
},
label:
{
Image(systemName: "star")
.foregroundColor(doc.isFav ? .yellow : .white)
}
)
}
}
}
}
}
.onAppear()
{
model.array.append(Doc())
model.array.append(Doc())
model.array.append(Doc())
model.array.append(Doc())
model.array.append(Doc())
model.array.append(Doc())
model.array.append(Doc())
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View
{
ContentView()
.previewDevice("iPhone 13")
}
}
为了从
Doc
的动作中变异 Button
,您需要一个 Binding<Doc>
。
您可以使用语法
Binding<[Doc]>
从现有 model
属性中获取 $model.array
。如果您将此 Binding
传递给 ForEach
,那么在 ForEach
内容中,您会得到 Binding<Doc>
而不是普通的 Doc
。
因此:
struct ContentView: View {
@ObservedObject var model = ViewModel.shared
var body: some View {
List {
ForEach($model.array, id: \.id) { $doc in
// ^ NEW! ^ NEW! ⬅️
HStack {
Text(doc.name)
Spacer()
Button {
doc.updateIsFav()
// also works now: doc.isFav.toggle()
} label: {
Image(systemName: doc.isFav ? "star.fill" : "star")
.foregroundColor(.yellow)
}
}
}
}.onAppear {
model.array.append(Doc())
model.array.append(Doc())
model.array.append(Doc())
model.array.append(Doc())
model.array.append(Doc())
model.array.append(Doc())
model.array.append(Doc())
}
}
}