03-主题|事件响应者链@iOS-响应者链与nextResponder详解

本文专门讲解 iOS 响应者链 的构成与传递:nextResponder(API 中为 next)的规则、链的路径示意、事件沿链传递与转发方式,以及如何通过重写 next 修改链。与「事件如何找到目标」配合阅读可参见 02-hitTest 与事件传递详解


一、响应者链是什么

响应者链 是由 UIRespondernext (文档与习惯上常称 nextResponder)串联起来的一条链。当第一响应者不处理某事件时,系统会把该事件传给 next,再传给 next.next,直到某个响应者处理或链结束(next == nil1

触摸事件 而言,第一响应者通常是 hit-test 得到的视图;对按键、摇动、编辑菜单等,第一响应者多为当前获得焦点的对象(如 UITextField)。


二、nextResponder 的构成规则

各子类对 next 的实现决定了链的走向。以下为 UIKit 中的典型规则 \[1]2

当前响应者 next 通常为
UIView 若该 view 是某个 UIViewController 的根 view (viewController.view),则 next 为该 UIViewController ;否则为 superview
UIViewController 若该 VC 的 view 是某 window 的根 view,则 next 为 UIWindow ;若该 VC 被其他 VC present,则 next 为 presenting ViewController
UIWindow UIApplication
UIApplication App Delegate(仅当 delegate 是 UIResponder 子类且不是 view、viewController 或 app 本身时)
链尾 nil

因此,典型链路径为:

text 复制代码
Hit-test View(或 First Responder)
  → 其 UIViewController(若存在)
  → 该 VC 的 view 的 superview
  → ... 逐级 superview ...
  → Window 的 rootViewController.view
  → rootViewController
  → UIWindow
  → UIApplication
  → App Delegate(若符合条件)
  → nil

三、响应者链路径示意

flowchart TB subgraph 视图层级 V[Hit-test View] P[Superview] R[Root View] end subgraph 链路径 V --> VC[UIViewController] VC --> P P --> R R --> VC2[Root VC] VC2 --> W[UIWindow] W --> App[UIApplication] App --> Del[App Delegate] Del --> nil[nil] end

简化理解:从被点中的 view 开始,先到管理它的 ViewController (若有),再到该 view 的 superview ,一路到 window → application → app delegate,最后到 nil。

3.1 响应者链知识结构(思维导图)

mindmap root((nextResponder 链)) 起点 hit-test view First Responder 规则 UIView → VC 或 superview UIViewController → superview 或 window UIWindow → UIApplication UIApplication → App Delegate / nil 传递 touchesBegan 等转发 target nil 沿链找 target 修改 重写 next 属性

3.2 泳道图:事件沿链传递的参与方

flowchart LR subgraph 视图层 V1[Hit-test View] V2[父 View] end subgraph 控制器层 VC[ViewController] end subgraph 窗口与应用 W[UIWindow] App[UIApplication] Del[App Delegate] end V1 -->|不处理则 next| VC VC -->|next| V2 V2 -->|next| W W --> App App --> Del

四、事件沿链传递与转发方式

4.1 触摸事件的传递

触摸事件(touchesBegan / touchesMoved / touchesEnded / touchesCancelled)会先发给 hit-test 得到的视图。若该视图未重写 这些方法,UIKit 的默认实现会把事件传给 next,即沿链向上传递 \[2]。

若视图重写 了触摸方法但希望「自己处理一部分,其余交给链上」:需显式调用 next 的对应方法,否则事件不会继续传递。

swift 复制代码
// 示例:将触摸事件交给下一响应者
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    // 可选:在此做自己的逻辑(如埋点、高亮)
    next?.touchesBegan(touches, with: event)
}

不调用 next?.touchesBegan(...) 则链在此中断,上层视图或 ViewController 不会收到该触摸。

商用场景示例 :自定义 Cell 内的某个 view 只做展示,希望点击「透传」到 Cell 或 VC 做统一处理(如整行点击跳详情);在自定义 view 中重写 touchesEnded 并调用 next?.touchesEnded(touches, with: event),由上层决定是否跳转。

延伸 :除系统 next 链外,业务层还常用 DelegateBlock/闭包函数封装快速枚举/for 循环 等方式做事件或回调的传递,与「链」形成互补。详见 06-响应者链传递方式与编程模式详解

4.2 Action 与 target-nil

UIControl 的 target-action 中,若 target 为 nil ,系统会从当前第一响应者开始,沿 next 查找第一个实现了对应 action 的响应者并调用,即 action 沿响应者链查找 target \[1]。编辑菜单(复制/粘贴等)也利用该机制在链上查找能执行 copy(_:)paste(_:) 等的对象。


五、修改响应者链:重写 next

可通过重写 next 属性改变链的走向,使事件或 action 先经过指定对象 \[1]。

swift 复制代码
// 示例:让某自定义 view 的 next 指向指定的 responder(如父 VC)
override var next: UIResponder? {
    return parentViewController ?? super.next
}

这样,当该 view 不处理事件时,事件会先传给 parentViewController,再按 parentViewController.next 继续。适用于希望「某视图的上级一定是某个 VC」的场景。

商用场景示例 :列表页中某个自定义 view(如卡片内嵌的容器)希望点击后一定由当前页的 ViewController 处理(如弹窗、路由),而不经过中间若干 superview;通过重写 next 指向 VC,可保证 Action 或 touches 先到达 VC。

遍历响应者链的调试/工具代码(Swift):

swift 复制代码
extension UIResponder {
    /// 打印从当前节点到链尾的整条响应者链,便于调试
    func printResponderChain() {
        var current: UIResponder? = self
        var level = 0
        while let r = current {
            print(String(repeating: "  ", count: level) + "\(type(of: r))")
            current = r.next
            level += 1
        }
    }
}
// 使用:在某个 view 或 VC 中调用 self.printResponderChain()

六、与 hit-test 的关系小结

阶段 方向 作用
Hit-Testing 自顶向下 确定「谁被点中」→ 该 view 为触摸的 first responder
Responder Chain 自底向上 从该 view 开始,沿 next 传递,直到有人处理或链结束

两者配合:hit-test 决定链的起点 ,next 决定链的走向与传递顺序 。详见 01-总纲02-hitTest 与事件传递。业务中「谁来处理」除依赖链外,还可通过 06-响应者链传递方式与编程模式详解 中的 Delegate、Block、函数封装、遍历传递等模式实现。


参考文献

1 Using responders and the responder chain to handle events - Alter the responder chain

2 UIResponder - Managing the responder chain (next)

相关推荐
SeaTunnel5 小时前
从 Python Script 地狱到标准化数据集成框架
大数据·开发语言·python·程序员·代码·seatunnel
Hilaku15 小时前
为什么 Cloudflare 能做到毫秒级冷启动,而其它云厂商却不行?
前端·javascript·程序员
用户29439182035316 小时前
Leno vs Python 性能对决:3-5 倍差距从何而来?
程序员
用户8524950718416 小时前
手把手教你理解 React:从端侧 AI 到组件化思维
程序员
SimonKing17 小时前
Agnes AI出桌面版了,可图可视频,免费用
java·后端·程序员
CodeSheep17 小时前
有这4个迹象,你就该离职了!
前端·后端·程序员
极客小俊18 小时前
我熬夜3天!终于搞定了VMware 2026官网免费下载的终极避坑指南
程序员
这个DBA有点耶1 天前
索引碎片与统计信息维护:执行计划突然变差的隐形杀手
mysql·程序员·架构
爱勇宝1 天前
AI不会淘汰所有人,但会淘汰这6种人
前端·后端·程序员
摸鱼师moko1 天前
AI 来了之后,我的心流状态去哪了
人工智能·程序员