引言:为什么“捕获”文本变化是基础?
\n\n想象一下:您正在编写一个食谱搜索应用。用户开始输入“意面”,而您的搜索应该立即触发,无需点击按钮。或者您正在制作一个注册表单,需要在用户输入第三个字母后立即高亮显示“密码太短”的错误。
\n\n在这两种情况下,您都需要知道UITextField中文本发生变化的精确时刻。这个问题在Stack Overflow上获得了数千次浏览——这并非没有原因。每个iOS开发者迟早都会遇到它。
\n\n在2025年,我们至少有4种方法来解决这个问题。有些是经过时间考验的老方法。其他则是Apple积极推广的新方法。在本文中,我们将分析所有选项,从经典到现代,我将展示针对特定任务应选择哪种方法。
\n\n开始吧!🚀
\n\n方法1. Target-Action:老派但有效
\n\n最简单易懂的方法,自iOS 2.0起就有效。是的,它已有超过15年的历史,但至今仍然适用。
\n\n其理念是UITextField继承自UIControl,因此能够生成事件。我们关注的是.editingChanged事件——它在每次文本更改时触发。
代码示例(UIKit + Storyboard或代码方式)
\n\nimport UIKit\n\nclass ViewController: UIViewController {\n\n @IBOutlet weak var searchTextField: UITextField!\n\n override func viewDidLoad() {\n super.viewDidLoad()\n // 为文本更改事件添加目标\n searchTextField.addTarget(self,\n action: #selector(textFieldDidChange(_:)),\n for: .editingChanged)\n }\n\n @objc func textFieldDidChange(_ textField: UITextField) {\n guard let text = textField.text else { return }\n print("文本已更改:\\(text)")\n // 此处可进行搜索、验证等操作\n }\n}\n\n优点:代码最少,无需遵循协议,运行速度快。
\n缺点:需要使用@objc——这是Swift的遗留特性。缺乏精细控制(例如,无法区分文本插入和删除)。
方法2. UITextFieldDelegate委托:控制每个字符
\n\n如果您不仅需要知道文本已更改,还需要影响更改(阻止输入、格式化电话号码),那么委托是您的选择。
\n\n这里的关键方法是textField(_:shouldChangeCharactersIn:replacementString:)。它在文本实际更改之前被调用。
示例:格式化电话号码
\n\nimport UIKit\n\nclass ViewController: UIViewController, UITextFieldDelegate {\n\n @IBOutlet weak var phoneTextField: UITextField!\n\n override func viewDidLoad() {\n super.viewDidLoad()\n phoneTextField.delegate = self\n }\n\n func textField(_ textField: UITextField,\n shouldChangeCharactersIn range: NSRange,\n replacementString string: String) -> Bool {\n\n // 只允许数字\n let allowedCharacters = CharacterSet.decimalDigits\n let characterSet = CharacterSet(charactersIn: string)\n guard allowedCharacters.isSuperset(of: characterSet) else {\n return false\n }\n\n // 限制长度为10个字符\n let currentText = textField.text ?? ""\n guard let stringRange = Range(range, in: currentText) else { return false }\n let updatedText = currentText.replacingCharacters(in: stringRange, with: string)\n return updatedText.count <= 10\n }\n\n // 额外:捕获文本已更改的时刻\n func textFieldDidChangeSelection(_ textField: UITextField) {\n print("文本已更新:\\(textFi