Swift子类重写属性为何可被继承链上层父类识别调用生效?
InputAccessoryEnabledTextField重写属性生效原理解答 基础前提说明
你自定义的子类继承链如下:
InputAccessoryEnabledTextField : UITextField : UIControl : UIView : UIResponder
核心重写实现代码:
private var myInputAccessoryController: UIInputViewController? override var inputAccessoryViewController: UIInputViewController? { get { myInputAccessoryController } set { myInputAccessoryController = newValue } }
这段代码生效没有任何隐藏的特殊处理,也没有违反继承规则,本质是面向对象多态特性的标准表现。
核心认知纠正
你之前默认的规则「只有子类能感知重写、父类无法感知」是完全错误的,Swift(以及UIKit底层的Objective-C)对可重写成员的动态派发规则是:
- 只要你创建的是子类
InputAccessoryEnabledTextField的实例,这个对象的实际类型自始至终都是子类,和你把它声明成什么类型(哪怕是向上转型为UITextField、UIResponder)没有任何关系。 - 对于所有可重写的实例属性/方法(Swift中非
final、非private、非静态的成员),只要是通过这个实例去访问,不管访问逻辑是写在父类代码里、子类代码里,还是UIKit系统框架代码里,动态派发机制都会找到该实例实际类型上最外层的重写实现来执行。
举个直白的例子:你继承了家里的厨艺,并且把传下来的「做番茄炒蛋」配方改了,只要是喊你这个人去做番茄炒蛋,不管喊你的人是你爷爷、你爸还是外面的朋友,你端出来的都是改了配方的版本,不可能突然变回你爸的原始配方。
代码实际运行流程
整个过程没有iOS文本输入系统的特殊定制逻辑,就是标准的多态调用链路:
- 用户点击输入框,你的
InputAccessoryEnabledTextField实例成为当前第一响应者 - UIKit键盘模块在弹出键盘前,只会拿到当前第一响应者的
UIResponder类型引用,根本不关心它是系统原生的UITextField还是你自定义的子类 - 键盘模块向这个对象读取
inputAccessoryViewController属性 - 动态派发机制识别到对象的实际类型是你自定义的子类,直接走你写的重写getter,返回你存在
myInputAccessoryController里的值 - 系统拿到返回的控制器,将其关联的视图展示在键盘上方
补充说明
你在Swift继承章节没找到对应说明很正常,因为这不是Swift独有的规则,是所有支持面向对象多态特性的语言(Objective-C、Java、C#等)通用的基础行为:重写的本质就是替换实例对应成员的实现,和调用方处于继承链的哪一层没有关系。
- 只有被标记为
final、private、静态的成员,因为不会走动态派发,子类的重写不会影响父类内部的调用逻辑。
内容的提问来源于stack exchange,提问作者clearlight
相关产品推荐
相关产品推荐

