I have this code:
import SwiftUI
import Combine
final class ViewModel: ObservableObject {
@Published var text = ""
var cancellables = Set<AnyCancellable>()
init() {
$text
.sink { completion in
} receiveValue: { text in
print("Text \(text)")
}.store(in: &cancellables)
}
}
struct ContentView: View {
@StateObject private var vm = ViewModel()
var body: some View {
TextField("Title", text: $vm.text)
}
}
#Preview {
ContentView()
}
What I have noticed, if I type one letter, i receive two values.
So at first it will just say Text. And if I type one letter, say letter A, output will look like this:
Text A
Text A
In some cases I saw it prints same value even more than two times.
I know I can use removeDuplicates but why is this actually happening?
Lots of mistakes:
Viewstruct hierarchy is the view model already don't try to use classes or you'll run into major issues.ObservableObjectyou shouldn't usesinkorcancellables, instead use.assignto complete the pipeline to an@Published. That way the lifetime is correct, i.e. the pipeline will be cancelled and tore down when the object deinits, which is what@StateObjectdoes. This can be used for a fetcher type object but not for view data.@StateObjectis for when you need a reference type in a@State, e.g. for a delegate or an async Combine pipeline, don't try to use them to make view models because that is the job of theViewstruct. If you upgrade to async/await and the.taskmodifier you don't need@StateObjectanymore.Your code fixed looks like this: