【问题标题】:Can you use a Publisher directly as an @ObjectBinding property in SwiftUI?可以直接使用 Publisher 作为 SwiftUI 中的 @ObjectBinding 属性吗?
【发布时间】:2019-06-22 20:24:37
【问题描述】:

在 SwiftUI 中,您可以将 Publisher 的实例直接用作 @ObjectBinding 属性,还是必须将其包装在实现 BindableObject 的类中?

let subject = PassthroughSubject<Void, Never>()
let view = ContentView(data:subject)

struct ContentView : View {
  @ObjectBinding var data:AnyPublisher<Void, Never>
}

// When I want to refresh the view, I can just call: 
subject.send(())

这不会为我编译,只会挂起 Xcode 11 Beta 2。但你应该被允许这样做吗?

【问题讨论】:

    标签: swift macos swiftui


    【解决方案1】:

    在您的视图正文中使用.onReceive 传递发布者,如下例所示,取自Data Flow Through SwiftUI - WWDC 2019 @ 21:23。在闭包内部,您更新了一个 @State 变量,而该变量又在主体中的其他位置被引用,这会导致主体在更改时被调用。

    【讨论】:

      【解决方案2】:

      您可以实现一个BindableObject,它将发布者作为初始化参数。

      并使用方便的函数扩展Publisher 以创建此BindableObject

      class BindableObjectPublisher<PublisherType: Publisher>: BindableObject where PublisherType.Failure == Never {
      
          typealias Data = PublisherType.Output
      
          var didChange: PublisherType
          var data: Data?
      
          init(didChange: PublisherType) {
              self.didChange = didChange
              _ = didChange.sink { (value) in
                  self.data = value
              }
          }
      }
      
      extension Publisher where Failure == Never {
          func bindableObject() -> BindableObjectPublisher<Self> {
              return BindableObjectPublisher(didChange: self)
          }
      }
      
      struct ContentView : View {
          @ObjectBinding var binding = Publishers.Just("test").bindableObject()
      
          var body: some View {
              Text(binding.data ?? "Empty")
          }
      }
      

      【讨论】:

      • 感谢您的建议,但是当我提到在类中包装 Publisher 时,这正是我希望避免的情况。我希望有一些我忽略的协议或现有 API。
      • BindableObjects 必须是一个类。所以这不是要避免的。
      最近更新 更多