Swiftui 如何在模型对象中使用@Binding var状态更改?

Swiftui 如何在模型对象中使用@Binding var状态更改?,swiftui,Swiftui,我有一个视图,其中包含一些用于选择日期属性的控件。我想在同级视图模型中使用该date属性在CoreData中搜索该日期的Schedule对象,或者在没有的情况下创建一个-asearchOrCreate方法。(我希望我可以使用@FetchRequest来实现这一点,但我还没有找到方法) 我已经将日期设置为@Binding变量,这样我就可以在Child2视图中获得视图更新,但是我还没有找到一种方法将状态更改传递给它的模型,以便它执行搜索或创建,因为didSet不适用于绑定。我是否没有正确地处理这个问

我有一个视图,其中包含一些用于选择日期属性的控件。我想在同级视图模型中使用该date属性在CoreData中搜索该日期的
Schedule
对象,或者在没有的情况下创建一个-a
searchOrCreate
方法。(我希望我可以使用
@FetchRequest
来实现这一点,但我还没有找到方法)

我已经将日期设置为
@Binding
变量,这样我就可以在
Child2
视图中获得视图更新,但是我还没有找到一种方法将状态更改传递给它的模型,以便它执行
搜索或创建
,因为
didSet
不适用于绑定。我是否没有正确地处理这个问题,是否应该使用
@Environment
变量或其他什么

struct ParentView: View {
  @State var day: Date = Date().noon
  var body: some View {
    VStack() {
      Child1View(day: $day)
      Child2View(day: day)
    }
  }
}

struct Child1View: View {
  @Binding var day: Date

  // code to select day
}

struct Child2View: View {
  var day: Date // I do not need to update the day in this view, 
  //just display it and use it in an object, so I did not use @Binding
  @StateObject private var viewModel = Child2ViewModel()

  ...
}

class Child2ViewModel: ObservableObject {
  var day: Date {
    didSet {
      // call searchOrCreate in CoreData for the Schedule object
    }

  @Published var schedule: Schedule
}
我发现,如果我将viewModel作为父视图的一部分并将其传递下去,那么它会破坏封装。理想情况下,我希望
Child2View
只需获得一个约会,然后从那里开始做它的事情

struct ParentView: View {
  @StateObject var viewModel = Child2ViewModel()
  var body: some View {
    VStack() {
      Child1View(day: $viewModel.day)
      Child2View(viewModel: viewModel)
    }
  }
}

struct Child2View: View {
  @ObservedObject private var viewModel: Child2ViewModel
  ...
}

class Child2ViewModel: ObservableObject {
  @Published var day = Date().noon {
    didSet {
      // call searchOrCreate in CoreData for the Schedule object
    }

  @Published var schedule: Schedule
}

您可以使用
onReceive
捕获父变量的更改并将其传递给ViewModel:

import Combine
import SwiftUI

struct ParentView: View {
    @State var day: Date = Date()

    var body: some View {
        VStack {
            Child1View(day: $day)
            Child2View(day: day)
        }
    }
}

struct Child2View: View {
    @StateObject private var viewModel = Child2ViewModel()
    var day: Date

    var body: some View {
        Text("Child2View")
            .onReceive(Just(day)) { // whenever the parent `day` changes, update the viewModel
                guard viewModel.day != $0 else { return }
                viewModel.day = $0
            }
    }
}

我试过了,它似乎进入了一个无限循环?我想这是因为
viewModel.day
有一个
didSet
,它更新
@发布的日程安排
,这会导致
Child2View
被重新绘制,从而
@绑定
再次接收。@SebastianVancea是的,
onReceive
在初始化视图时也会被触发。您可以添加一个guard语句来检查值是否更改-查看更新的答案。视图将被重绘两次似乎是多余的,一次是在
日更新,一次是在
@发布的计划中,但我想这不是一个大问题。但是,为什么需要在
Child2View
中绑定一天?我不需要在该视图中对它进行任何更新,它看起来像。onReceive被调用,即使它是一个简单的变量。@SebastianVancea我没有注意到它-是的,如果不更改值,那么它就不必是
@Binding