A ViewModel
class has a sourceProperty
that is being edited by the TextField
. That property is @Published
. I'd like to pass it to the Logic
class which has an initializer with Binding<String>
. That class will be listening to the sourceProperty
changes, react on them and set it's output to the @Published output
property.
How can I pass @Published sourceProperty
as an initializer parameter to the Logic
class?
Relevant code:
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)
}
}
So far I'm getting the following error:
Cannot convert value of type 'Published.Publisher' to expected argument type 'Binding'
The goal is to use a change in the object's own property to trigger a method invocation in another object and then bind that second object's output to some view.
View Layer:
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)
}
}
If I understand your question correctly, you are probably looking for something like that:
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)
}
}