在 Combine 响应式编程框架中,Subscriber(订阅者) 是数据流的终点,负责接收 Publisher(发布者)发送的值、完成事件和错误信息,并执行最终处理逻辑Apple Developer Documentation。它与 Publisher 通过Subscription(订阅) 建立连接,实现背压(Backpressure) 控制,让订阅者能够控制接收数据的速度
public protocol Subscriber<Input, Failure> : CustomCombineIdentifierConvertible {
订阅者期望接收的值类型
associatedtype Input
订阅者可能接收的错误类型(永不失败用Never)
associatedtype Failure : Error
1. 订阅成功时调用,接收Subscription对象
func receive(subscription: Subscription)
2. 接收单个值,返回Demand表示还能接收多少值
func receive(_ input: Input) -> Subscribers.Demand
3. 接收完成事件(正常完成或错误终止)
func receive(completion: Subscribers.Completion<Failure>) }
Demand是 Combine 的核心特性,实现背压控制,让订阅者决定接收数据的节奏
public enum Demand : Equatable, CustomStringConvertible {
/// 不接收任何数据
case none
/// 接收n个数据
case ax(Int)
/// 制接收数据(常用)
case mited
}
Demand 规则
-
初始请求:必须在
receive(subscription:)中调用subscription.request(_:),否则不会收到任何数据 -
累积效应:Demand 是累积的,例如先请求
.max(2),再返回.max(3),总共可接收 5 个数据 -
自动调整:
receive(_:)返回的 Demand 会更新订阅者的剩余需求 -
完成终止:收到完成事件后,所有未处理的 Demand 自动失效
内置 Subscriber 类型
-
sink 通过闭包处理值和完成事件,返回
AnyCancellable用于取消订阅var cancellables = Set<AnyCancellable>() // 处理值和完成/错误 [1,2,3].publisher.sink { ompletion in switch completion { case .finished: print("完成") case .failure(let error): print("错误: \(error)") } } eceiveValue: { value in print("收到值: \(value)") }.store(in: &cancellables) -
Assign(属性绑定)直接将值绑定到对象的属性,适合 UI 更新场景
class UserViewModel { @Published var username: String = "" var cancellables = Set<AnyCancellable>() } let vm = UserViewModel() ["Alice", "Bob", "Charlie"].publisher .assign(to: \.username, on: vm) .store(in:&vm.cancellables) // 监听属性变化 vm.$username .sink { print("用户名更新: \($0)") }.tore(in: &vm.cancellables) -
AnySubscriber(类型擦除)包装任意 Subscriber,隐藏具体类型,适用于需要抽象订阅者的场景
let anySubscriber = AnySubscriber<String, Never>(receiveSubscription: { subscription insubscription.request(.unlimited) }, receiveValue: { value -> Subscribers.Demand in print("AnySubscriber 收到: \(value)") return .none }, receiveCompletion: { completion in print("AnySubscriber 完成: \(completion)") }) Just("测试AnySubscriber").subscribe(anySubscriber) -
自定义 Subscriber 实现
class SumSubscriber: Subscriber { // 定义接收的数据类型和错误类型 typealias Input = Int typealias Failure = Never private var total: Int = 0 private var subscription: Subscription? 1. 订阅成功时调用 func receive(subscription: Subscription) { self.subscription = subscription // 请求所有数据 subscription.request(.unlimited) } // 2. 接收单个值 func receive(_ input: Int) -> Subscribers.Demand { total += input print("当前总和: \(total)") // 继续接收所有数据 return.unlimited } // 3. 接收完成事件 func receive(completion: Subscribers.Completion<Never>) { print("最终总和: \(total)") print("完成状态: \(completion)") // 清理资源 subscription = nil } } // 使用自定义订阅者 let sumSubscriber = SumSubscriber() [1, 2, 3, 4, 5].publisher.subscribe(sumSubscriber) -
Subscription 管理与取消
取消订阅的三种方式
-
自动取消:
AnyCancellable被销毁时自动调用cancel() -
手动取消:调用
AnyCancellable的cancel()方法 -
集合管理:使用
Set<AnyCancellable>统一管理多个订阅var cancellables = Set<AnyCancellable>() let cancellable = Timer.publish(every: 1, on: .main, in: .common) .autoconnect() .sink { print($0) } // 手动取消 cancellable.cancel() // 或添加到集合管理 cancellable.store(in:&cancellables) // 清空集合取消所有订阅 cancellables.removeAll()
-