Combine

1. Combine 的简介 #

Combine 是 Apple 在 iOS 13+/macOS 10.15+ 引入的声明式响应式编程框架,专注于处理异步和事件驱动的流数据。它与传统的回调机制不同,通过 Publisher-Subscriber 模式(发布-订阅模式)来管理事件,从而实现更简单、模块化和可组合的代码。

特点: #

  • 响应式编程: 它提供了数据流的声明式接口,更易于处理异步事件(如网络请求、用户输入、定时器等)。
  • 功能强大: 通过丰富的操作符,可以对事件流进行过滤、映射、合并等操作,实现流式数据处理。
  • 类型安全: 事件数据的流动是通过泛型管理的,开发者可以借助编译器的类型检查。
  • 广泛的系统集成: 它可以与 UIKit、SwiftUI、NotificationCenter、URLSession 等系统框架无缝集成。

2. Combine 的体系结构 #

Combine 的核心概念主要包括以下几个关键部分:

2.1 Publisher(发布者) #

  • 定义: Publisher 是 Combine 的数据源,负责发布数据流或事件流。

  • 每个 Publisher 有两种可能的输出:

    1. 值(Value): 正常数据流中的值;
    2. 完成(Completion): 数据流结束或发生错误(成功或失败)。
  • Combine 提供了许多内置的 Publisher

    • 例如 URLSession 的网络请求结果、NotificationCenter 的通知、Timer 等。
  • 特点:

    • Publisher 不会主动发送数据,只有当有 订阅者Subscriber)订阅时,数据流才会开始。

2.2 Subscriber(订阅者) #

  • 定义: 订阅者(Subscriber)是 Combine 中的消费者,负责接收 Publisher 发布的值和结束信号(成功或失败)。

  • 生命周期:

    1. 当订阅者订阅发布者时,会建立数据流的订阅连接。
    2. Subscriber 会收到发布者的每个事件(即数据流中的值)。
    3. 数据发布完成或错误发生后,数据流结束。
  • Combine 提供了一些现成的订阅方法,如 .sink().assign()

2.3 Operator(操作符) #

  • 定义: Operator 是 Combine 的最强大特性,可以对数据流进行组合、过滤、映射、延迟等操作。
  • 作用:
    • 操作符在 PublisherSubscriber 之间,作用于数据流,本质上是中间处理器。
    • 每个 Operator 都会生成一个新的 Publisher,以便链式操作。

常见操作符: #

操作符功能
map对每个数据值应用指定的变换,比如类型转换。
filter只允许满足条件的元素通过。
flatMap把一个 Publisher 转换为另一个 Publisher 类型。
merge合并多个发布者的数据流为一个数据流。
combineLatest合并多个发布者的最新数据值。
debounce在时间范围内限制事件流。
catch捕获错误并提供替代的 Publisher
eraseToAnyPublisher将复杂的发布者转换为通用的发布者类型。

2.4 Cancellable (取消订阅器) #

  • 定义: Cancellable 是 Combine 的订阅管理工具。它表示一个有效的数据流绑定,允许在不需要时取消订阅并释放资源。
  • 作用: 避免未解除的事件流导致的内存泄漏。

2.5 Subjects(主题) #

  • 定义: Subject 是 Combine 中 既是发布者,也是订阅者 的特殊对象,允许我们在现有的代码中插入 Combine 的流式逻辑。
  • 类型:
    1. PassthroughSubject
      • 直接发送数据,所有订阅者都会接收。
      • 数据在没有订阅者时不会存储。
    2. CurrentValueSubject
      • 存储最近一次值的数据主题。
      • 当订阅者第一次订阅时,接收到的就是当前值。

3. 使用 Combine:基本用法与示例 #

3.1 数据发布与订阅的基本流程 #

  1. 创建一个 Publisher(发布者)。
  2. Publisher 处理并转换数据(通过操作符)。
  3. 使用 Subscriber(订阅者)接收最终的数据。

示例:创建一个简单的数据流 #

  1. 使用 Just 发布单值数据:
import Combine

let publisher = Just("Hello, Combine!")
let cancellable = publisher.sink { value in
    print(value)
}

输出结果:

Hello, Combine!
  • 解释:
    • Just 是一个简单的发布者,用于发布单个值并完成。
    • .sink 是订阅者,用于接收 Publisher 发布的值。

3.2 模拟实时事件流(输入数据、过滤和转化) #

import Combine

let numbers = (1...10).publisher

numbers
    .filter { $0 % 2 == 0 }       // 筛选偶数
    .map { "\($0) is even" }      // 转换为字符串
    .sink { print($0) }           // 订阅并打印每个值

输出:

2 is even
4 is even
6 is even
8 is even
10 is even

3.3 与 Subjects 结合(手动发布数据) #

Subject 适用于手动控制数据的发布。

import Combine

let subject = PassthroughSubject<String, Never>()

let cancellable = subject
    .sink { print("Received: \($0)") }

subject.send("First Event") // 手动发布事件
subject.send("Second Event")
subject.send("Third Event")

输出:

Received: First Event
Received: Second Event
Received: Third Event

3.4 实现网络请求(URLSession 与 Combine 集成) #

通过 Combine 处理网络请求,代码更优雅。

import Combine
import Foundation

let url = URL(string: "https://jsonplaceholder.typicode.com/posts/1")!

let cancellable = URLSession.shared.dataTaskPublisher(for: url)
    .map(\.data)                                 // 提取响应数据
    .decode(type: [String: Any].self, decoder: JSONDecoder()) // 解码 JSON 数据
    .sink(receiveCompletion: { completion in     // 处理完成事件
        print("Completion: \(completion)")
    }, receiveValue: { value in                  // 处理值数据
        print("Data received: \(value)")
    })

4. Combine 的适用场景(什么时候使用) #

4.1 适用场景 #

  1. 处理异步任务:

    • 像网络请求、定时器、文件系统事件等,Combine 提供了基于流的统一接口。
  2. 响应式用户交互:

    • 比如处理文本输入(UITextField)、搜索结果(防抖/节流)等:

      import Combine
      
      let textPublisher = NotificationCenter.default
          .publisher(for: UITextField.textDidChangeNotification)
          .map { ($0.object as? UITextField)?.text ?? "" }
          .filter { !$0.isEmpty } // 如果内容为空则忽略
          .sink { print("User typed: \($0)") }
      
  3. 状态管理:

    • 数据和视图之间的绑定,比如 SwiftUI 和 Combine 结合。
  4. 处理多个数据流:

    • 合并多个独立的事件流,例如同时处理多个 API 调用。

4.2 不适合的场景 #

  1. 简单任务:

    • 对非常简单的任务(如单次逻辑、同步方法调用等),使用 Combine 会显得过于冗余。
  2. 低版本支持:

    • Combine 仅支持 iOS 13+/macOS 10.15+,对于需要支持更低版本的 App 不适合。
  3. 紧密耦合的场景:

    • 比如单点对单点的通信(回调函数或代理模式更合适)。

5. Compare with NotificationCenter and Delegate #

FeatureCombineNotificationCenterDelegate
通信模式发布/订阅发布/订阅一对一
松耦合否(强绑定)
方式声明式、流式处理基于通知名称传播函数回调
数据处理能力强(支持丰富操作符)弱(只广播通知)
异步任务处理极强无(通常结合其他工具)一般

6. Combine 总结 #

Combine 适用于现代的响应式数据流处理场景。它具有 声明式编程、数据流操作符、多事件合并 等特点,非常适合复杂的异步任务和模块化开发。在需要以较小成本解耦事件处理、优化 UI 连动、数据驱动的场景时,Combine 是非常强大的工具!