📖 前言

在 iOS 中大型项目开发中,观察者模式(Observer Pattern)是最常用的行为型设计模式。它主要用于对象之间消息通知、状态监听、事件同步,实现代码解耦。

iOS 开发中随处可见观察者思想:NotificationCenterKVOCombineRxSwift 全部底层基于观察者模式。

本文详细讲解:观察者模式概念、核心原理、两种实现方式、项目真实使用场景、完整可复用代码、优缺点以及开发规范,适合面试背诵、项目开发、博文沉淀。

一、观察者模式核心概念

1.1 什么是观察者模式?

观察者模式属于行为型设计模式,定义了一种一对多的依赖关系:

当一个对象(被观察者)状态发生改变时,所有依赖它的对象(观察者)都会自动收到通知并更新。

1.2 核心角色

  1. 被观察者(Subject):维护观察者数组、提供添加/移除/通知方法。

  2. 观察者(Observer):接收回调、执行更新逻辑。

1.3 核心思想

  • 松耦合:被观察者、观察者互相不硬依赖

  • 一对多广播:一处改变,多处响应

  • 事件驱动:无需轮询,被动接收通知

二、iOS 中常见观察者实现方式

Swift 项目开发中,观察者模式分为两大类:

2.1 系统原生实现

  • NotificationCenter:全局通知,跨页面、跨模块通信

  • KVO:监听属性变化

  • Combine:Swift 原生响应式框架(SwiftUI 主流)

2.2 第三方/手写实现

  • RxSwift/RxCocoa:企业级主流响应式

  • 手写原生观察者:轻量自定义监听、无依赖

三、手写最简观察者模式(底层原理版)

为了彻底理解底层,下面手写一套纯原生、无任何依赖观察者模型,看懂等于吃透原理。

3.1 步骤1:定义观察者协议

import Foundation
// 观察者协议
protocol Observer: AnyObject {
    func update(message: String)
}

3.2 步骤2:创建被观察者

// 被观察者
class Subject {
    // 持有所有观察者(弱引用防止内存泄漏)
    private var observers: [Observer] = []
    
    // 添加观察者
    func addObserver(_ observer: Observer) {
        observers.append(observer)
    }
    
    // 移除观察者
    func removeObserver(_ observer: Observer) {
        observers.removeAll { $0 === observer }
    }
    
    // 广播通知
    func notify(message: String) {
        observers.forEach {
            $0.update(message: message)
        }
    }
}

3.3 步骤3:创建具体观察者

// 观察者A
class ObserverA: Observer {
    func update(message: String) {
        print("观察者A收到消息:\(message)")
    }
}

// 观察者B
class ObserverB: Observer {
    func update(message: String) {
        print("观察者B收到消息:\(message)")
    }
}

3.4 使用示例

// 创建被观察者
let subject = Subject()

// 创建观察者
let observerA = ObserverA()
let observerB = ObserverB()

// 注册监听
subject.addObserver(observerA)
subject.addObserver(observerB)

// 发出广播(所有观察者自动回调)
subject.notify(message: "用户登录成功")

3.5 输出结果

观察者A收到消息:用户登录成功
观察者B收到消息:用户登录成功

四、项目高频实战写法(NotificationCenter)

开发中最常用、最简单的观察者就是系统通知,适合跨页面、无耦合通信。

4.1 发送通知

// 任意位置发送
NotificationCenter.default.post(name: NSNotification.Name("UserLoginSuccess"), object: nil)

4.2 监听通知

// 在需要监听的页面接收
NotificationCenter.default.addObserver(self, selector: #selector(loginEvent), name: NSNotification.Name("UserLoginSuccess"), object: nil)

@objc func loginEvent() {
    print("监听到用户登录,刷新个人中心")
}

4.3 移除监听(必须操作)

deinit {
    NotificationCenter.default.removeObserver(self)
}

五、进阶:Combine 响应式观察者(SwiftUI 主流)

Swift 原生响应式框架,无第三方依赖,适合 MVVM、SwiftUI 数据流绑定。

import Combine

class UserViewModel {
    // 被观察者:发布者
    @Published var isLogin: Bool = false
}

// 监听
let vm = UserViewModel()
vm.$isLogin.sink { isLogin in
    print("当前登录状态:\(isLogin)")
}
// 改变状态、自动触发监听
vm.isLogin = true

六、观察者模式 在 iOS 项目真实使用场景

以下为中大型Swift项目高频业务场景

  1. 用户登录/退出登录全局监听
    登录后刷新个人中心、购物车、权限、首页数据。

  2. 暗黑模式、语言切换
    全局发送通知,所有页面自动刷新UI。

  3. 网络状态监听
    有无网络、WiFi/流量切换,统一弹窗提示。

  4. IM聊天消息推送
    收到消息,聊天列表、红点、会话实时刷新。

  5. 订单状态变更
    支付成功、发货、签收,多页面同步刷新状态。

  6. 埋点、全局事件统计
    一处发送、多处统计上报,业务解耦。

七、观察者模式优缺点

7.1 优点

  • 完全解耦:发布者、观察者互不依赖

  • 一对多广播:一次通知,多处响应

  • 动态注册:运行时随意添加、移除监听

  • 遵循开闭原则:新增观察者无需修改原有代码

7.2 缺点

  • 消息无序:无法控制接收顺序

  • 内存泄漏风险:不及时移除监听会强引用残留

  • 消息链路隐蔽:通知过多难以排查调用链路

八、开发注意事项(避坑⚠️)

  1. 必须移除监听:Notification、KVO 一定要在 dealloc 销毁,防止内存泄漏。

  2. 禁止滥用全局通知:大型项目通知过多,排查难度极高。

  3. 循环引用防范:自定义观察者一定要使用 weak 弱引用存储观察者。

  4. 复杂业务优先 Combine/RxSwift:原生通知适合简单事件,复杂数据流使用响应式。

九、总结

  1. 观察者模式是一对多事件广播,核心是状态变动自动通知。

  2. iOS 三大实现:手写观察者、Notification、Combine

  3. 适合:登录状态、主题切换、订单、IM、网络状态等全局事件。

  4. 开发重点:解耦、弱引用、及时销毁监听


更多推荐