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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:31:31