Reputation: 1545
I noticed that
textField.publisher(for: \.text)
delivers events when editing finishes, but not for every character/editing change. How do I get a Publisher, that sends evens for every change? In ReactiveSwift it would be
textField.reactive.continousTextValues()
And in RxSwift it would be just (How do you get a signal every time a UITextField text property changes in RxSwift)
textField.rx.text
Approaches I took:
publisher(for:options:)
method, but there are no appropriate options for the desired outcome.textField.addTarget(self, action: #selector(theTextFieldDidChange), for: .editingChanged)
(UITextField text change event)@Published
variables instead, hiding were the values actually came from - (or did I miss something?).I have no clue at the moment, how to do this and I feel the tendency to go back to ReactiveSwift, but I wanted to ask you, before taking this step backwards.
Upvotes: 12
Views: 12634
Reputation: 633
In case of a UITextField you can use this extension:
extension UITextField {
func textPublisher() -> AnyPublisher<String, Never> {
NotificationCenter.default
.publisher(for: UITextField.textDidChangeNotification, object: self)
.map { ($0.object as? UITextField)?.text ?? "" }
.eraseToAnyPublisher()
}
}
use as: textField.textPublisher()
Upvotes: 16
Reputation: 6547
If this is what you are looking for, I guess UITextField
emits both notifications and controlevents, so you can achieve that by listening to notifications for example:
import UIKit
import Combine
class ViewController: UIViewController {
@IBOutlet private var textField: UITextField!
var cancellables = Set<AnyCancellable>()
override func viewDidLoad() {
super.viewDidLoad()
let textFieldPublisher = NotificationCenter.default
.publisher(for: UITextField.textDidChangeNotification, object: textField)
.map( {
($0.object as? UITextField)?.text
})
textFieldPublisher
.receive(on: RunLoop.main)
.sink(receiveValue: { [weak self] value in
print("UITextField.text changed to: \(value)")
})
.store(in: &cancellables)
}
}
Let me know if this was your actual goal.
Upvotes: 6
Reputation: 7591
Unfortunately, Apple didn't add publishers for this to UIKit and because UIControl doesn't implement KVO the publisher(for:)
publisher doesn't work quite as expected. If you're okay with adding a dependency to your project there are a couple of good UIControl publishers here.
Alternatively, you could implement your own publisher that does this, or subscribe to textfield changes the old school way.
Upvotes: 6
Reputation: 639
You can always create a custom Publisher for your needs. For example, here I've created TextField publisher, that wraps textFieldDidChange action for textField and sends String after each character entered/deleted! Please, copy the link, SO doesn't parse it:
https://github.com/DmitryLupich/Combine-UIKit/blob/master/CombineCustomPublishers/🚜%20Publishers/TextFieldPubisher.swift
Upvotes: 5