Multiple UITextFields and textDidChangeNotification notification

Viewed 1847

I was playing with Combine framework lately and was wondering if it is possible to create some smart extension to get text changes as Publisher.

Let's say I've got two UITextFields:

firstTextField.textPub.sink {
    self.viewModel.first = $0
}

secondTextField.textPub.sink {
    self.viewModel.second = $0
}

where first and second variable is just `@Published var first/second: String = ""

extension UITextField {
    var textPub: AnyPublisher<String, Never> {
        return NotificationCenter.default
            .publisher(for: UITextField.textDidChangeNotification)
            .map {
                guard let textField = $0.object as? UITextField else { return "" }
                return textField.text ?? ""
            }
            .eraseToAnyPublisher()
    }
}

This doesn't work because I'm using shared instance of NotificationCenter so when I make any change to any of textFields it will propagate new value to both sink closures. Do you think is there any way to achieve something similar to rx.text available in RxSwift? I was thinking about using addTarget with closure but it would require using associated objects from Objective-C.

2 Answers

I figured this out. We can pass object using NotificationCenter and then filter all instances that are not matching our instance. It seems to work as I expected:

extension UITextField {
    var textPublisher: AnyPublisher<String, Never> {
        NotificationCenter.default
            .publisher(for: UITextField.textDidChangeNotification, object: self)
            .compactMap { $0.object as? UITextField }
            .map { $0.text ?? "" }
            .eraseToAnyPublisher()
    }
}

I would suggest you add subscribers to the view modal, and connect them a text field publisher within the context of the view controller.

NotificationCenter is useful to dispatch events app-wide; there's no need to use it when connecting items that are fully owned by the View Controller. However, once you've updated the view modal it may make sense to publish a 'View Modal Did Change' event to NotificationCenter.

Related