Swift Combine - 如何获得一个发布者,为 UITextField 的文本属性的每个字符更改提供事件
Posted
技术标签:
【中文标题】Swift Combine - 如何获得一个发布者,为 UITextField 的文本属性的每个字符更改提供事件【英文标题】:Swift Combine - How to get a Publisher that delivers events for every character change of UITextField's text property 【发布时间】:2020-03-11 16:05:45 【问题描述】:我注意到了
textField.publisher(for: \.text)
在编辑完成时提供事件,但不是针对每个字符/编辑更改。我如何获得发布者,为每次更改发送偶数? 在 ReactiveSwift 中它会是
textField.reactive.continousTextValues()
在 RxSwift 中它只是 (How do you get a signal every time a UITextField text property changes in RxSwift)
textField.rx.text
我采取的方法:
正在检查publisher(for:options:)
方法,但没有合适的选项来获得所需的结果。
添加目标/操作textField.addTarget(self, action: #selector(theTextFieldDidChange), for: .editingChanged)
(UITextField text change event)
通过界面生成器连接动作,与上一步基本相同,这都会导致额外的工作和混乱的代码。
观看有关 Combine 的 2019 年 WWDC 视频。他们不是在处理文本字段,而是使用@Published
变量,隐藏值实际上来自 - (或者我错过了什么?)。
目前我不知道如何做到这一点,我觉得有回到 ReactiveSwift 的倾向,但我想在退后一步之前问你。
【问题讨论】:
为什么不用TextField
而不是UITextField
?这会在每个字符更改时更新其 text
绑定。
OP 很有可能不(想要)使用 SwiftUI
【参考方案1】:
如果是 UITextField,您可以使用此扩展:
extension UITextField
func textPublisher() -> AnyPublisher<String, Never>
NotificationCenter.default
.publisher(for: UITextField.textDidChangeNotification, object: self)
.map ($0.object as? UITextField)?.text ?? ""
.eraseToAnyPublisher()
用作:textField.textPublisher()
【讨论】:
【参考方案2】:不幸的是,Apple 没有为此向 UIKit 添加发布者,并且由于 UIControl 没有实现 KVO,publisher(for:)
发布者无法按预期工作。如果您可以在项目中添加依赖项,那么有几个不错的 UIControl 发布者here。
或者,您可以实现自己的发布者来执行此操作,或者订阅 textfield 更改旧的学校方式。
【讨论】:
【参考方案3】:您始终可以根据需要创建自定义发布者。例如,在这里我创建了 TextField 发布者,它为 textField 包装了 textFieldDidChange 操作,并在输入/删除每个字符后发送字符串!请复制链接,所以不会解析它:
https://github.com/DmitryLupich/Combine-UIKit/blob/master/CombineCustomPublishers/?%20Publishers/TextFieldPubisher.swift
【讨论】:
【参考方案4】:如果这是您要查找的内容,我猜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)
让我知道这是否是你的实际目标。
【讨论】:
以上是关于Swift Combine - 如何获得一个发布者,为 UITextField 的文本属性的每个字符更改提供事件的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Combine + Swift 复制 PromiseKit 风格的链式异步流
如何通过另一个可观察对象观察已发布的属性 - Swift Combine
如何在 Swift 中使用 Combine 读取 JSON 错误对象的属性值?
Swift Combine:如何从发布者列表中创建单个发布者?
Swift Combine:如何将 `AnyPublisher<[Foo], *>` 转换为 `AnyPublisher<Foo, *>`?