可以直接使用 Publisher 作为 SwiftUI 中的 @ObjectBinding 属性吗?

Posted

技术标签:

【中文标题】可以直接使用 Publisher 作为 SwiftUI 中的 @ObjectBinding 属性吗?【英文标题】:Can you use a Publisher directly as an @ObjectBinding property in SwiftUI? 【发布时间】: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。但你应该被允许这样做吗?

【问题讨论】:

【参考方案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 必须是一个类。所以这不是要避免的。

以上是关于可以直接使用 Publisher 作为 SwiftUI 中的 @ObjectBinding 属性吗?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Swift Combine 创建一个 Timer Publisher

让自定义 Publisher 在 Swift Combine 上的不同 DispatchQueue 上运行

Swift Publisher 5.5.3安装教程

如何使用 combine Publisher 更改线程?

PHP JSON 数据到 Xcode Swift 数组

是否可以自动提取 Apple News / iCloud News Publisher 分析数据?