Swift 4中如何在shouldChangeCharactersIn获取UITextField字段名
获取UITextField变量名的可靠方案
我明白你现在的需求——在shouldChangeCharactersIn代理方法里拿到UITextField的变量名,而且tag已经被用来存储其他数据,没法再用它来区分文本框。你之前尝试的runtime遍历ivar的路子其实不太靠谱,因为Swift的属性在编译后会有底层命名变化,而且这种方式局限性很强(比如局部创建的文本框根本不在当前类的ivar列表里)。我给你两个更稳妥的方案:
方案一:用关联对象给UITextField添加名称属性
这种方式相当于给系统的UITextField类动态加一个自定义属性,用来存储你想要的名称,既不影响原有功能,也不需要改动太多代码。
首先给UITextField写个扩展:
import ObjectiveC // 定义一个唯一的关联对象key private var TextFieldNameKey: UInt8 = 0 extension UITextField { // 自定义的name属性,用来存储文本框的变量名 var name: String? { get { return objc_getAssociatedObject(self, &TextFieldNameKey) as? String } set { objc_setAssociatedObject(self, &TextFieldNameKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } }
然后在创建文本框的时候(或者IBOutlet的viewDidLoad里)设置名称:
// 代码创建文本框的情况 let usernameTextField = UITextField(frame: CGRect(x: 20, y: 100, width: 300, height: 40)) usernameTextField.name = "usernameTextField" // 这里设置你代码里的变量名 usernameTextField.delegate = self // IBOutlet的情况,在viewDidLoad里设置 override func viewDidLoad() { super.viewDidLoad() usernameTextField.name = "usernameTextField" emailTextField.name = "emailTextField" }
最后在代理方法里直接获取:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { if let fieldName = textField.name { print("当前编辑的文本框是:\(fieldName)") // 这里根据不同的fieldName做业务处理 } return true }
方案二:用字典映射文本框和名称
如果不想用runtime关联对象,也可以提前把所有文本框和对应的名称存在一个字典里,代理方法里直接通过文本框实例查字典。
在ViewController里定义一个字典:
var textFieldNameMap: [UITextField: String] = [:]
然后在viewDidLoad里初始化映射:
override func viewDidLoad() { super.viewDidLoad() textFieldNameMap[usernameTextField] = "usernameTextField" textFieldNameMap[emailTextField] = "emailTextField" }
代理方法里的使用:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { if let fieldName = textFieldNameMap[textField] { print("当前编辑的文本框是:\(fieldName)") } return true }
为什么原来的runtime遍历方法不推荐?
Swift的属性在编译后会生成带前缀的底层ivar(比如你代码里的usernameTextField,底层ivar可能是_usernameTextField),而且如果是IBOutlet的话,ivar是编译器自动合成的,名字可能和你IBOutlet的名称不一致。另外,如果文本框是局部变量或者在其他类里创建的,根本不会出当前类的ivar列表里,这种方法就完全失效了。
内容的提问来源于stack exchange,提问作者Robert Smith
相关产品推荐
相关产品推荐

