在需要@Binding 的地方传递@Published(SwiftUI、Combine)

Posted

技术标签:

【中文标题】在需要@Binding 的地方传递@Published(SwiftUI、Combine)【英文标题】:Pass @Published where @Binding is required (SwiftUI, Combine) 【发布时间】:2021-10-15 02:39:15 【问题描述】:

ViewModel 类有一个 sourceProperty 正在由 TextField 编辑。该属性是@Published。我想将它传递给Logic 类,该类有一个带有Binding<String> 的初始化程序。该类将监听sourceProperty 的变化,对它们做出反应并将其输出设置为@Published output 属性。

如何将@Published sourceProperty 作为初始化参数传递给Logic 类?

相关代码:

final class ViewModel 
    @Published var sourceProperty: String = ""
    private var logic: Logic?

    init() 
        self.logic = Logic(data: $sourceProperty)
        $logic.output.sink(result in 
            print("got result: \(result)")
        )
    



final class Logic: ObservableObject 
    private var bag = Set<AnyCancellable>()
    @Published var output: String = ""
    @Binding var data: String
    init(data: Binding<String>) 
        self._data = data

        $data.sink( newValue in 
            output = newvalue + "ABCDE"
        ).store(in: &bag)
    

到目前为止,我收到以下错误:

无法将“Published.Publisher”类型的值转换为预期值 参数类型“绑定”

目标是使用对象自身属性的更改来触发另一个对象中的方法调用,然后将第二个对象的输出绑定到某个视图。

视图层:

public struct ViewLayer: View 
    @Binding private var sourceProperty: String

    public init(_ placeholder: String,
                sourceProperty: Binding<String>,
    ) 
        self.placeholder = placeholder
        self._sourceProperty = sourceProperty
    

    public var body: some View 
        TextField(placeholder, text: $sourceProperty)
    

 

【问题讨论】:

@Binding 只能在 `Views.如果您的问题也包括视图层,那会更容易提供帮助。 确定你想要Binding吗?您正在尝试在其上使用sink,这是来自Publisher 不,我不确定是否需要binding。我想要实现的是将两个类连接在一起,这样当 sourceproperty 被写入(通过视图)时,Logic 类将对该更改做出反应并更新它自己的属性。 我同意上面的评论——包括视图层可能很好。听起来您绝对不需要绑定——可能只需将发布者传递给Logic。但是,我很难理解为什么你也需要嵌套的ObservableObjects。这似乎很可疑。我明白为什么你的ViewModel 会是ObservableObject,但不知道为什么Logic 会。而现在,你的代码正好相反。 添加简化视图层为例 【参考方案1】:

如果我正确理解您的问题,您可能正在寻找类似的东西:

final class ViewModel: ObservableObject 
    
    @Published var sourceProperty: String = ""
    private lazy var logic = Logic(data: $sourceProperty)
    private var cancellable: AnyCancellable?

    init() 
        cancellable = logic.$output
            .sink  result in
                print("got result: \(result)")
            
    



final class Logic: ObservableObject 
    
    @Published private(set) var output: String = ""
    
    init(data: Published<String>.Publisher) 
        data
            .map  $0 + "ABCDE" 
            .assign(to: &$output)
    

【讨论】:

完美,这看起来达到了我的目标。谢谢!

以上是关于在需要@Binding 的地方传递@Published(SwiftUI、Combine)的主要内容,如果未能解决你的问题,请参考以下文章

06.Binding(绑定)03

将 @State 属性的 @Binding 值从容器视图传递到其子视图

将观察对象的投影值的属性传递给@Binding

SwiftUI 将@Published viewmodel 对象值传递给@Binding

传递一个 Binding 和一个常量字符串作为参数

Java并发编程发布与逸出