软件设计

Swift Delegate 与 Observer:什么时候该用哪个?完整对比

进行 iOS 开发时,你会不断遇到 Delegate 模式。

4 分钟阅读
Swift Delegate 与 Observer:什么时候该用哪个?完整对比 封面图

进行 iOS 开发时,你会不断遇到 Delegate 模式。

每次使用 UITableView、UITextField 都要添加 delegate,你可能都想过:“为什么是 delegate?直接用闭包或通知不行吗?”

尤其学完 Observer 模式后,反而更容易混淆。两者都是“发生事情时发出通知”的结构,到底有什么不同?

先说结论。

Delegate 是一种 1:1 通信:一个对象把事情委托给唯一的一个对象,“这件事交给你了”。

Observer 是一种 1:N 广播:多个订阅者同时订阅同一个事件。

理解这一句话,你就已经掌握了一半。今天我们结合代码彻底梳理两者的区别。


什么是 Delegate 模式?

Delegate 的意思就是“委托”。

把自己不方便处理的事情交给一个值得信赖的对象:“你替我决定吧。”

可以用生活中的例子来理解。

我想预订餐厅,但懒得亲自打电话,于是请一位助理帮忙:“替我预订一下。”

这里的助理就是 Delegate。委托方一个人,受托方也一个人,正好是 1:1。

在 Swift 中,我们通过协议约定这种关系。

// 在协议中定义要委托的工作
protocol OrderDelegate: AnyObject {
    func didFinishOrder(_ menu: String)
}

class Restaurant {
    weak var delegate: OrderDelegate?  // 只指定一个对象
    func order(_ menu: String) {
        delegate?.didFinishOrder(menu)  // 只通知这一个对象
    }
}

这里要注意,delegate不是数组,而是一个属性

既然只委托给一个对象,自然只保存一个。这就是 Delegate 是 1:1 的原因。

而且还有weak。相互强引用会形成 retain cycle,导致内存泄漏,因此 Delegate 通常使用 weak 引用。


它和 Observer 模式有什么不同?

Observer 就是“观察者”。

事件发生时,通知会一次性发送给正在观察它的多个对象

继续沿用刚才的助理例子。

这次,我把餐厅开业的消息广播给整个街区:“今晚开业!”

听众可能有十个人,也可能有一百个人。我不关心谁在听,只负责把消息发出去。

这就是 1:N 广播,也就是 Observer 模式。

在 iOS 中,NotificationCenter就是典型例子。

// 事件发生 → 广播给所有订阅者
NotificationCenter.default.post(name: .storeOpen, object: nil)

// 感兴趣的对象分别订阅
NotificationCenter.default.addObserver(
    self, selector: #selector(handleOpen),
    name: .storeOpen, object: nil)

发送方不知道接收者是谁,只是加上名称后发送出去。

接收方也由多个对象分别订阅。

彼此无需了解,因此耦合度较低;但缺点是很难追踪当前是谁在接收通知。

亲自写过代码后,我才终于理解了
亲自写过代码后,我才终于理解了

Delegate 与 Observer 一目了然的对比

只用文字说明容易混淆,所以我整理成了表格。

1:1 委托和 1:N 广播,用图看就很清楚
1:1 委托和 1:N 广播,用图看就很清楚
分类 Delegate Observer
通信方式 1:1(委托给一个对象) 1:N(广播给多个对象)
是否了解对方 彼此明确了解 彼此无需了解
典型示例 UITableViewDelegate NotificationCenter
响应(返回值) 容易接收 较难接收
耦合度 相对较高
跟踪/调试 容易 比较困难

关键在于:“是否需要得到响应?”

使用 Delegate 时,询问“这个单元格应该多高?”对方会返回一个值。这是双向交流的结构。

Observer 只是发送后结束。发送方不关心谁会如何响应。


那么什么时候该用哪个?

这是我在实际项目中使用后总结出的判断标准。

使用 Delegate 的场景

  1. 只需要与一个对象通信时
  2. 需要从对方获取返回值时(例如单元格数量、高度)
  3. 屏幕跳转等顺序和流程明确时

使用 Observer 的场景

  1. 一个事件需要多个页面同时响应时
  2. 登录状态变化、切换深色模式等全局事件
  3. 发送方和接收方无需互相了解时

例如登录成功后,首页、个人中心和顶部横幅都要同时变化时,Delegate 就不够用了。

因为只能委托给一个对象,要连接三个地方会让代码变得杂乱。

这时用 Observer 广播一次“登录成功了!”会清爽得多。

相反,“点击了输入框中的确认按钮”这种 1:1 场景,Delegate 或闭包才是正确选择。

在白板上用箭头画出来,就会容易很多
在白板上用箭头画出来,就会容易很多

总结

即使两者看起来相似,只要想想“要通知多少人”,选择就会变得简单。

一个人用 Delegate,多个人用 Observer。记住这一条标准就够了。

下次写代码时,试着应用今天学到的内容吧。当只停留在脑中的知识真正变成手上的经验,模式就会容易很多。加油!

延伸阅读