swiftui - 与 SwiftUI 和 Combine 的双向绑定(bind)

标签 swiftui combine

我正在尝试找出如何在父子关系中的两个 ViewModel 之间正确传递一个对象或一组值,以便在更新子 ViewModel 时,更改会冒泡回到父级。

当仅使用 SwiftUI View 并直接绑定(bind)到商店时,这非常简单,但我想将字段验证等业务逻辑与 SwiftUI View 分开。

下面的代码显示了当父项更新时子项更新(如预期的那样),但我需要以某种方式将子项中更改的值传回给父项。我是移动应用程序开发的新手并且仍在学习,所以我确定我错过了一些非常简单的东西。

import SwiftUI
import Combine

struct Person: Hashable {
  var givenName: String
  var familyName: String
}

// my person store - in the real app it's backed by coredata
class PersonStore: ObservableObject {
  @Published var people: [Person] = [
    Person(
      givenName: "Test",
      familyName: "Person"
    )
  ]
  static let shared = PersonStore()
}

// app entrypoint
struct PersonView: View {
  @ObservedObject var viewModel: PersonView_ViewModel = PersonView_ViewModel()

  var body: some View {
    NavigationView {
      VStack {
        List(viewModel.people.indices, id: \.self) { idx in
          NavigationLink(destination: PersonDetailView(viewModel: PersonDetailView_ViewModel(personIndex: idx))) {
            Text(self.viewModel.people[idx].givenName)
          }
        }
      }
    }
  }
}

class PersonView_ViewModel: ObservableObject {
  @Published var people: [Person] = PersonStore.shared.people
}

// this is the detail view
struct PersonDetailView: View {
  @ObservedObject var viewModel: PersonDetailView_ViewModel

  var body: some View {
    Form {
      Section(header: Text("Parent View")) {
        VStack {
          TextField("Given Name", text: self.$viewModel.person.givenName)
          Divider()
          TextField("Family Name", text: self.$viewModel.person.familyName)
        }
      }
      PersonBasicDetails(viewModel: PersonBasicDetails_ViewModel(person: viewModel.person))
    }
  }
}

// viewmodel associated with detail view
class PersonDetailView_ViewModel: ObservableObject {
  @Published var person: Person

  init(personIndex: Int) {
    self.person = PersonStore.shared.people[personIndex]
  }
}

// this is the child view - in the real app there are multiple sections which are conditionally rendered
struct PersonBasicDetails: View {
  @ObservedObject var viewModel: PersonBasicDetails_ViewModel

  var body: some View {
    Section(header: Text("Child View")) {
      VStack {
        TextField("Given Name", text: self.$viewModel.person.givenName)
        Divider()
        TextField("Family Name", text: self.$viewModel.person.familyName)
      }
    }
  }
}

class PersonBasicDetails_ViewModel: ObservableObject {
  @Published var person: Person

  init(person: Person) {
    self.person = person
  }
}

struct PersonView_Previews: PreviewProvider {
  static var previews: some View {
    PersonView()
  }
}

最佳答案

在网络上的大多数 SwiftUI TextField 示例中,绑定(bind)是通过使用 @State 变量提供的,该变量会为您创建一个 Binding 实例.

但是,您也可以使用 Binding 构造函数创建自定义绑定(bind)。下面是一个示例:

TextField(
  "Given Name",
  text: Binding(
    get: { self.$viewModel.person.givenName },
    set: { self.$viewModel.person.givenName = $0 }))

关于swiftui - 与 SwiftUI 和 Combine 的双向绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59074995/

相关文章:

swift - 为什么 `Publishers.Map`会急切的消费上游值呢?

swiftui - 为什么receiveValue block Combine订阅没有retain cycle

swiftui - 是什么导致在此代码中调用 updateUIView()?

ios - 如何调整 UIHostingController 的大小以包装它的 SwiftUI View ?

text - 关注 VStack 中的下一个 TextField

SwiftUI 数组 - 忽略 nil 值

swift - 在 SwiftUI 中延迟重复动画,并在完全自动反向重复循环之间

swift - URLSession.shared.dataTaskPublisher 不适用于 IOS 13.3

ios - List 对象的 SwiftUI 分页

swift - 将带有状态变量的函数传递给 subview