Swift Combine - 如何获得为 UITextField 的文本属性的每个字符更改提供事件的发布者

the*_*utz 7 uitextfield ios swift combine

我注意到

textField.publisher(for: \.text)
Run Code Online (Sandbox Code Playgroud)

在编辑完成时传递事件,但不是针对每个字符/编辑更改。我如何获得一个发布者,它会为每次更改发送事件?在 ReactiveSwift 中,它将是

textField.reactive.continousTextValues()
Run Code Online (Sandbox Code Playgroud)

而在 RxSwift 中,它只是(如何在 RxSwift 中每次 UITextField 文本属性更改时获得信号

textField.rx.text
Run Code Online (Sandbox Code Playgroud)

我采取的方法:

  • 检查publisher(for:options:)方法,但对于所需的结果没有合适的选项。
  • 添加目标/操作textField.addTarget(self, action: #selector(theTextFieldDidChange), for: .editingChanged)UITextField 文本更改事件
  • 通过接口构建器连接操作,与上一步基本相同,这两者都会导致额外的工作和混乱的代码。
  • 观看 2019 年关于 Combine 的 WWDC 视频。他们没有处理文本字段,而是使用@Published变量,隐藏值实际上来自 - (或者我错过了什么?)。

我目前不知道如何做到这一点,我觉得有回到 ReactiveSwift 的趋势,但我想问你,在退步之前。

kpr*_*ter 16

如果是 UITextField,您可以使用此扩展:

  extension UITextField {
    func textPublisher() -> AnyPublisher<String, Never> {
        NotificationCenter.default
            .publisher(for: UITextField.textDidChangeNotification, object: self)
            .map { ($0.object as? UITextField)?.text  ?? "" }
            .eraseToAnyPublisher()
    }
  }
Run Code Online (Sandbox Code Playgroud)

用作:textField.textPublisher()


don*_*als 6

不幸的是,Apple 没有为此向 UIKit 添加发布者,并且由于 UIControl 没有实现 KVO,因此publisher(for:)发布者无法按预期工作。如果您愿意向项目添加依赖项,这里有一些很好的 UIControl 发布者。

或者,您可以实现自己的发布商来执行此操作,或者订阅文本字段以更改旧式方式。


den*_*lor 6

如果这是您正在寻找的,我想UITextField会发出通知和控制事件,因此您可以通过监听通知来实现这一点,例如:

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

让我知道这是否是您的实际目标。