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

ken*_*nyc 9 macos swift swiftui

在 SwiftUI 中,您可以将 a 的实例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(())
Run Code Online (Sandbox Code Playgroud)

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

mal*_*hal 25

在您的视图主体中,使用.onReceive像下面的示例一样传入发布者,取自Data Flow Through SwiftUI - WWDC 2019 @ 21:23。在闭包内更新一个@State 变量,它反过来在主体中的其他地方被引用,这导致主体在更改时被调用。

在此处输入图片说明


Ugo*_*ino 6

您可以实现一个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")
    }
}
Run Code Online (Sandbox Code Playgroud)