You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:11:38