Swift Combine - 如何让 Publisher 为 UITextField 文本的每个字符更改传送事件 属性

Swift Combine - How to get a Publisher that delivers events for every character change of UITextField's text property

我注意到

textField.publisher(for: \.text)

在编辑完成时提供事件,但不是针对每个 character/editing 更改。我如何获得发布者,它会为每次更改发送消息? 在 ReactiveSwift 中它将是

textField.reactive.continousTextValues()

而在 RxSwift 中它只是 (How do you get a signal every time a UITextField text property changes in RxSwift)

textField.rx.text

我采用的方法:

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

您始终可以根据需要创建自定义发布者。例如,我在这里创建了 TextField 发布者,它包装了 textField 的 textFieldDidChange 操作,并在每个字符 entered/deleted 之后发送 String!请复制 link,所以不解析它:

https://github.com/DmitryLupich/Combine-UIKit/blob/master/CombineCustomPublishers/%20 出版商/TextFieldPubisher.swift

不幸的是,Apple 没有为此向 UIKit 添加发布者,并且因为 UIControl 没有实现 KVO,所以 publisher(for:) 发布者没有按预期工作。如果您愿意为您的项目添加依赖项,那么有几个不错的 UIControl 发布者 here.

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

如果这是您要查找的内容,我猜 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( {
                ([=10=].object as? UITextField)?.text
            })
        
        textFieldPublisher
            .receive(on: RunLoop.main)
            .sink(receiveValue: { [weak self] value in
                print("UITextField.text changed to: \(value)")
            })
            .store(in: &cancellables)
    }
}

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

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

  extension UITextField {
    func textPublisher() -> AnyPublisher<String, Never> {
        NotificationCenter.default
            .publisher(for: UITextField.textDidChangeNotification, object: self)
            .map { ([=10=].object as? UITextField)?.text  ?? "" }
            .eraseToAnyPublisher()
    }
  }

用作:textField.textPublisher()