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

Swift 5中单个类持有多个delegate是否合理?有何优缺点?

同一个类中声明持有多个弱引用delegate是完全合规合理的Swift实现方式,不存在语法或设计原则上的错误,是否适用完全取决于具体业务场景

你给出的示例代码本身在内存安全层面是没有问题的:两个协议都约束了AnyObject(仅允许类类型实现),delegate属性都用weak修饰,不会产生循环引用。唯一的问题是delegate1、delegate2的命名完全没有语义,实际开发中要替换成能体现职责的命名。

适用场景

当一个类需要向外部分发不同职责维度的事件时,拆分多个delegate是非常符合设计原则的做法。举个最常见的例子:系统的UITextField本身就同时持有delegate(负责编辑行为、文本变化回调)和输入辅助项相关的多个委托引用,很多音视频播放器、列表组件也会拆分多个delegate处理不同领域的回调:

  • playbackDelegate 只负责播放状态相关回调(播放/暂停/进度更新/播放结束)
  • renderDelegate 只负责画面渲染相关回调(首帧渲染/分辨率切换/渲染卡顿)
  • networkDelegate 只负责网络相关回调(缓冲状态/拉流错误/地址过期)

这种场景下如果把所有回调塞到同一个臃肿的delegate协议里,反而会让实现方被迫依赖一堆和自身职责无关的接口。

写法优势

  • 完全符合接口隔离原则:不同职责的回调拆分到独立的小协议中,调用方只需要实现自己关心的协议即可,不需要依赖包含几十上百个方法的大而全的协议
  • 内存安全可控:只要遵循「协议加AnyObject约束、delegate属性用weak修饰」的规则,多delegate写法和传统单delegate写法的内存安全性完全一致,不会出现循环引用
  • 职责边界清晰:语义化命名的delegate属性能直接体现对应回调的负责领域,代码可读性更高,后续维护时不需要在冗长的大协议里翻找对应逻辑
  • 配置灵活度高:可以针对不同delegate单独配置回调派发队列、回调策略,比如网络相关回调派发到后台队列,UI相关的播放状态回调固定派发到主队列,互不干扰

存在的弊端

  • 拆分层级不合理时会提升使用成本:如果为了拆而拆,把关联度极高的逻辑拆成五六个delegate,外部初始化这个类的时候需要逐个给delegate属性赋值,很容易出现遗漏,使用体验很差
  • 无法替代多播委托场景:注意这种每个delegate属性单独持有一个引用的写法,和「一个事件通知多个观察者」的多播委托是完全不同的设计。如果同一个事件需要同时发给多个对象,这种写法实现不了,应该选择通知中心、Combine或者自定义多播委托容器
  • 容易出现职责混乱:如果拆分的时候没有划清不同delegate的职责边界,导致多个协议里出现大量功能重叠的回调方法,反而会让逻辑变得混乱,调用方也不知道该实现哪个协议才对

编写注意事项

  • 所有作为delegate的协议必须加上AnyObject约束,否则weak修饰符会直接编译报错,同时也能避免值类型实现协议带来的预期外行为
  • 所有delegate属性必须用weak修饰,否则一定会产生循环引用
  • 不要用delegate1、delegate2这种无意义命名,delegate的属性名要直接体现它负责的职责域
  • 如果多个delegate对应的回调职责高度重叠,不要强行拆分,合并到同一个协议里反而更易维护

内容的提问来源于stack exchange,提问作者SadDeveloper

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 01:45:43