Swift中非Objective-C风格观察函数底层实现探究——以didAddSubview为例
嘿,这个问题问到点子上了!很多开发者天天用didAddSubview(_:),但很少深究它的底层逻辑,尤其是你提到的「非Objective-C风格观察」这点,刚好戳中了UIKit这类框架回调的本质。我来给你拆解清楚:
一、先理清楚原生触发的核心路径
当你调用view.addSubview(subview)时,UIKit内部的执行流程是一套硬编码的逻辑,完全不需要依赖外部观察机制:
- 第一步:做前置校验——比如检查subview是不是已经有父视图、是不是当前视图本身、有没有处于动画锁定状态等,避免非法操作
- 第二步:更新视图层级——把subview加入当前视图内部维护的
subviews集合(注意这不是普通的NSMutableArray,UIKit对它做了线程安全、布局缓存相关的特殊处理),同时设置subview的superview属性为当前视图,同步更新响应链、布局优先级等关联信息 - 第三步:主动触发回调——在所有层级操作完成后,UIKit会直接调用当前视图的
didAddSubview(subview)方法,同时也会调用subview的didMoveToSuperview()方法
二、底层实现的本质:框架内置的硬编码回调
你提到不想用通知或者Objective-C KVO,而原生的didAddSubview(_:)刚好就是这种非OC风格的实现——它不是通过动态监听属性变化来触发的,而是框架在核心方法里主动调用的扩展钩子:
- 它不需要你注册观察者,只要你重写了这个方法,UIKit就会在对应的时机自动执行——因为
addSubview(_:)的内部实现里,已经写死了要触发这个回调的逻辑 - 从底层代码来看,UIKit的核心视图方法(比如
addSubview、removeFromSuperview)大多是用Objective-C或C++实现的,在这些方法的末尾,会直接调用对应的回调方法。我给你写个简化版的伪代码模拟一下:
- (void)addSubview:(UIView *)subview { // 前置校验逻辑 if (subview.superview == self) return; if (subview == self) return; // ... 其他合法性检查 // 更新视图层级关联 [self->_internalSubviews addObject:subview]; subview->_superview = self; // ... 更新响应链、布局缓存等内部状态 // 主动触发回调 [self didAddSubview:subview]; [subview didMoveToSuperview]; }
这个伪代码里,didAddSubview:就是直接被调用的,没有任何外部观察的中间层,属于框架主动给开发者预留的扩展入口。
三、和KVO/通知的本质区别
为了帮你更清晰地理解,我对比下它和你提到的两种实现方式的不同:
- 和KVO的区别:KVO是基于Objective-C Runtime的动态注入机制,会修改被观察对象的类,在属性setter里插入钩子代码;但UIKit的
subviews是内部私有属性,官方明确禁止用KVO观察(会有兼容性问题),而且didAddSubview:的触发时机是在层级操作完成后,不是属性变化的瞬间 - 和通知的区别:通知是松散耦合的发布-订阅模式,需要手动发送和注册观察者;而
didAddSubview:是UIView类内部的生命周期钩子,耦合度更高,但执行效率也更高,属于框架直接和开发者代码的对接
四、自己实现类似的非OC风格观察机制
如果你想在自己的自定义组件里实现类似的逻辑,完全可以参考UIKit的思路,用主动触发回调的方式,不需要依赖OC Runtime:
比如在Swift里实现一个自定义视图的回调:
class CustomContainerView: UIView { // 自定义回调闭包,方便外部监听 var didAddSubviewCallback: ((UIView) -> Void)? override func addSubview(_ subview: UIView) { super.addSubview(subview) // 主动触发自定义回调 didAddSubviewCallback?(subview) // 也可以调用自定义的方法 self.onSubviewAdded(subview) } private func onSubviewAdded(_ subview: UIView) { // 这里写自己的处理逻辑 print("新添加了子视图:\(subview)") } }
这种方式就是完全的非OC风格,靠硬编码的主动调用实现观察,和UIKit的原生逻辑一致。
内容的提问来源于stack exchange,提问作者progammingBeignner
相关产品推荐
相关产品推荐

