I am currently building a search field that should execute some action when its value changes. Here is my view:
struct SearchView: View {
@ObservedObject var vm = SearchViewModel()
var body: some View {
VStack {
TextField("Type something", text: $vm.text)
.font(.title)
.padding()
.background(Color.white)
.cornerRadius(10)
.shadow(color: .gray, radius: 4, x: 0, y: 2)
HStack {
Spacer()
Button("Paste") {
vm.pasteText()
}
.buttonStyle(.borderedProminent)
Button("Clear") {
vm.clearText()
}
.buttonStyle(.borderless)
}
.padding(.top)
Spacer()
}
.padding(.horizontal)
}
}
And here is the view model:
class SearchViewModel: ObservableObject {
@Published var text = ""
private var subscriptions = Set<AnyCancellable>()
init() {
$text
.sink(receiveValue: { value in
print("receiveValue: \(value)")
})
.store(in: &subscriptions)
}
func pasteText() {
self.text = "Text"
}
func clearText() {
self.text = ""
}
}
When I run the app and type something, for example, a letter "A", I get the following output:
receiveValue:
receiveValue:
receiveValue:
receiveValue: A
receiveValue: A
The first empty value is received once the view is created. Then, two empty values are received once I focused on the field. Finally, once I typed letter "A", I got two print statements again.
So, I have a few questions:
It's also interesting, when I press the paste/clear buttons I only get a single output per action.
You could use removeDuplicates
to avoid receiving identical values a few times in a row and dropFirst
to ignore the first empty String
but not the subsequent ones.
$text
.removeDuplicates()
.dropFirst()
.sink { value in
print("receiveValue: \(value)")
}
.store(in: &subscriptions)