微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

将 List 的 cell 属性绑定到 Observable ViewModel

如何解决将 List 的 cell 属性绑定到 Observable ViewModel

我有一个列表,它的单元格内容绑定到一个模型。模型内容来自网络。我使用@StateObject + @ObservableObject + @Published 机制来应用绑定如下:

视图模型是:

class viewmodel: ObservableObject {
   @Published var employees = [Employee]()
}

视图是:

import SwiftUI

struct PresentView: View {
   
   @StateObject var viewmodel = Presenterviewmodel("https://www.somelink.com/")
   
   var body: some View {
       NavigationView {
           List(self.viewmodel.employees) { employee in
               EmployeeView(name: employee.name,role: employee.title.rawValue)
           }
           .listStyle(GroupedListStyle())
           .onAppear() {
               viewmodel.load() // URL combine fetch
           }
           .navigationBarTitle("Company")
       }
   }
}

struct EmployeeView: View {
   
   var name: String   // <---- I want to attribute it a @Binding
   var role: String   // <---- I want to attribute it a @Binding

   var body: some View {
       HStack {
           Image(imageName)
           vstack {
               Text("\(name)")
                   .font(.headline)
               Text("\(role)")
                   .font(.subheadline)
           }
       }
   }
}

('Employee' 携带一些字符串和一个枚举并符合 Identifiable 和 Decodable)

我的问题:

为什么我不能将 EmployeeView 的属性声明为 @Binding? (它喊道:“无法将 'String' 类型的值转换为预期的参数类型 'Binding”,我猜他期待来自调用者的“@State”,但我无法在这里提供)。 毕竟应用@Binding 是有意义的:我的视图模型中已经有了一个真实来源和一个双向绑定。如果我让 EmployeeView 没有 @Binding,这意味着每个 List 加载都会复制每个单元格内容,这是多余的,因为我的模型中已经有了真实的来源。 我做错了什么?

解决方法

毕竟应用@Binding 是有意义的:我的视图模型中已经有了真实来源和双向绑定。

这不是正确的思考方式。如果子视图没有修改内容,则不需要绑定。是的,数据会被复制,但这不会破坏事实来源 - 事实来源仍然是视图模型,无论那里有多少不可变副本


但是如果子视图正在修改内容,那么您需要使用 @Binding 注释它修改的属性,并且您需要将 Binding<String> 传递给它们。现在您直接传递 String - 因此出现错误。

在 SwiftUI 中绑定列表项有点奇怪(在我看来)。您可以采取多种方法。其中之一是迭代数组的索引而不是元素,并使用 $employees[index] 获取对元素的绑定。

我还建议将整个 employee 对象传递给 EmployeeView 而不是它的单个属性。

List(self.viewModel.employees.indices,id: \.self) { index in
   EmployeeView(employee: self.$viewModel.employees[index])
}

然后,您需要在 @Binding 的属性上使用 EmployeeView

struct EmployeeView: View {
   @Binding var employee: Employee

   var body: some View {
      VStack {
         TextField("",text: $employee.name) // ex: modifies the name
         Text(employee.role) // ex: doesn't modify the role
      }
   }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。