二、Combine框架源码解析
1. 架构设计
1.1 整体架构
Combine 采用协议导向的设计,核心是三个协议:
Publisher (发布者)
↓
Subscription (订阅关系)
↓
Subscriber (订阅者)
数据流:
Publisher → Subscription → Subscriber
↑ ↓
└────────── 反馈 ──────────┘
1.2 核心协议层次
// 第一层:Publisher 协议
protocol Publisher {
associatedtype Output
associatedtype Failure: Error
func receive<S: Subscriber>(subscriber: S)
}
// 第二层:Subscription 协议
protocol Subscription: Cancellable {
func request(_ demand: Subscribers.Demand)
}
// 第三层:Subscriber 协议
protocol Subscriber: CustomCombineIdentifierConvertible {
associatedtype Input
associatedtype Failure: Error
func receive(subscription: Subscription)
func receive(_ input: Input) -> Subscribers.Demand
func receive(completion: Subscribers.Completion<Failure>)
}
1.3 内部架构分层(三层视图)
Combine 从内到外可以理解为协议层 → 实现层 → 调度层,三者共同决定「谁在何时、何地、以何种方式」传递事件。
架构分层示意:
┌─────────────────────────────────────────────────────────────────────────────┐
│ 调度层 (Scheduler) │
│ · 决定事件在哪个线程/队列执行 │
│ · subscribe(on:) / receive(on:) / 时间类操作符(debounce, delay) 依赖调度器 │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 实现层 (Concrete Types) │
│ · Just / Future / PassthroughSubject / Publishers.Map / Sink / Assign ... │
│ · 每个操作符 = 新 Publisher + 中间 Subscriber,形成链式实现 │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 协议层 (Protocols) │
│ · Publisher:定义「可被订阅」的契约 │
│ · Subscription:定义「请求/取消」的契约 │
│ · Subscriber:定义「接收值/完成」的契约 │
└─────────────────────────────────────────────────────────────────────────────┘
- 协议层:只规定接口(Output/Failure、receive(subscription/input/completion)、request(demand)),不关心具体类型。
- 实现层:所有
Just、Map、Filter、Sink等具体类型都遵循上述协议,并通过「包装上游 + 向下游转发」组成链条。 - 调度层:由
Scheduler协议抽象(如DispatchQueue、RunLoop),操作符在需要时把回调投递到指定调度器执行,从而控制线程与时机。
1.4 响应者链(订阅链)
一次 publisher.map(...).filter(...).sink(...) 会在内部形成一条从上游到下游的订阅链:每一环都是一个 Publisher,下游订阅上游,最末端是真正的 Subscriber(如 Sink)。值沿这条链自上而下传递,Demand 可自下而上反馈。
响应者链结构图:
[上游] [操作符] [操作符] [终端]
Just → Map<Int,String> → Filter<String> → Sink
│ │ │ │
│ subscribe │ subscribe │ subscribe │
│ ◄───────────────┼────────────────────┼───────────────┤
│ │ │ │
│ receive(S) │ receive(S) │ receive(S) │
│ 创建 Subscription │ │
│ 向下游传 subscription │ │
│ │ request(demand) │ │
│ │ ◄──────────────────┼───────────────┤
│ receive(1) │ receive("1") │ receive("1") │
│ │ receive(2) │ (若通过) │
│ │ receive("2") │ receive("2") │
│ │ ... │ ... │
│ receive(.finished) │ │
│ │ receive(completion) │
│ │ │ receive(completion)
│ │ │ │
▼ ▼ ▼ ▼
要点:
- 谁是谁的上游/下游:例如
Just(1).map { "\($0)" }中,Just是上游,Publishers.Map<Just<Int>, String>是下游;.sink时,Sink是整条链的最终下游。 - 订阅方向:下游调用
upstream.receive(subscriber: self),即「下游作为 Subscriber 被上游接收」,从而建立订阅。 - 值传递方向:上游通过
subscriber.receive(value)把值交给下游;若下游是另一个操作符的包装 Subscriber,该 Subscriber 会做变换后再调用自己的下游的receive,形成链式传递。 - Demand 反馈:
receive(_ input:)返回Subscribers.Demand,上游(或中间层)根据该返回值决定是否继续发送、发送多少,实现背压。
1.5 信息流流转(从订阅到结束)
从调用 subscribe(如 .sink(...))到收到完成,整条链上的调用顺序是固定的,可归纳为建立订阅 → 请求 Demand → 多次下发值 → 下发完成。
阶段一:建立订阅(自上而下)
sink(...) 被调用
│
▼
Sink 作为 Subscriber 被传给最下游 Publisher(如 Filter)
│
▼
Filter.receive(subscriber: Sink) → 创建 FilterSubscriber,包装 Sink
│
▼
FilterSubscriber 作为 Subscriber 被传给上游(Map)
│
▼
Map.receive(subscriber: FilterSubscriber) → 创建 MapSubscriber,包装 FilterSubscriber
│
▼
MapSubscriber 作为 Subscriber 被传给上游(Just)
│
▼
Just.receive(subscriber: MapSubscriber) → 创建 Subscription(如 SimpleSubscription)
│
▼
subscriber.receive(subscription:) 从 Just 一路向下传递到 Sink
│
▼
Sink 保存 subscription,并调用 subscription.request(.unlimited) [或 .max(n)]
阶段二:请求与下发(上游 → 下游)
Subscription.request(demand) [由 Sink 发起]
│
▼
上游(如 Just)开始向 MapSubscriber 发送值:subscriber.receive(1)
│
▼
MapSubscriber.receive(1) → transform(1) → downstream.receive("1")
│
▼
FilterSubscriber.receive("1") → 若通过,downstream.receive("1");否则 return .max(1)
│
▼
Sink.receive("1") → 执行 sink 的 receiveValue 闭包;返回 .none 或新 Demand
│
▼
(可选)Demand 沿链返回,上游据此决定是否继续 send
阶段三:完成
上游发送 subscriber.receive(completion: .finished) 或 .failure(e)
│
▼
沿链向下传递 completion,每一层收到后转发给 downstream
│
▼
Sink.receive(completion:) → 执行 receiveCompletion 闭包;置空 subscription
│
▼
订阅结束,链上各层可释放资源
信息流总览图(时序):
Subscriber (Sink) 中间层 (Map/Filter) Publisher (Just)
│ │ │
│ receive(subscriber:) │ │
│ ◄─────────────────────────────────────────────────────────────┤
│ │ receive(subscriber:) │
│ │ ◄────────────────────────────┤
│ │ │
│ receive(subscription:) │ receive(subscription:) │ create
│ ◄─────────────────────────────────────────────────────────────┤
│ │ │
│ request(.unlimited) │ request(...) │
│ ─────────────────────────────────────────────────────────────► │
│ │ │
│ receive(1) │ receive(1) → "1" │ send 1
│ ◄─────────────────────────────────────────────────────────────┤
│ receive("1") [若经 Map] │ │
│ ◄─────────────────────────────────────────────────────────────┤
│ receive(completion:) │ receive(completion:) │ send completion
│ ◄─────────────────────────────────────────────────────────────┤
│ │ │
1.6 核心协议关系小结
| 角色 | 职责 | 在链中的位置 |
|---|---|---|
| Publisher | 提供 receive(subscriber:),被订阅时创建 Subscription 并下发给 Subscriber | 链中每一环(含操作符)都是 Publisher |
| Subscription | 响应 request(_ demand) 向上游要数据;实现 cancel() 结束订阅 | 通常由最上游(如 Just)创建,引用传给下游 |
| Subscriber | 接收 receive(subscription:)、receive(_ input:)、receive(completion:);通过返回值反馈 Demand | 链中每一环的「下游」都是 Subscriber;终端是 Sink/Assign |
理解上述内部架构、响应者链、信息流后,再看任意操作符的源码,都可以套用「新 Publisher 包装上游 + 新 Subscriber 包装下游,在 receive(_ input:) 里做变换再转发」这一模式。
Mermaid 数据流图(可选渲染):
sequenceDiagram
participant S as Sink(Subscriber)
participant F as Filter
participant M as Map
participant J as Just(Publisher)
S->>F: receive(subscriber: S)
F->>M: receive(subscriber: FilterSub)
M->>J: receive(subscriber: MapSub)
J->>M: receive(subscription)
M->>F: receive(subscription)
F->>S: receive(subscription)
S->>S: subscription.request(.unlimited)
S->>F: request 向上传递
F->>M: request
M->>J: request
J->>M: receive(1)
M->>F: receive("1")
F->>S: receive("1")
J->>M: receive(completion)
M->>F: receive(completion)
F->>S: receive(completion)
2. Publisher协议实现
2.1 Publisher协议定义
public protocol Publisher {
/// 发布的值类型
associatedtype Output
/// 错误类型
associatedtype Failure: Error
/// 接收订阅者
func receive<S>(subscriber: S)
where S: Subscriber,
S.Input == Output,
S.Failure == Failure
}
2.2 Just实现分析
public struct Just<Output>: Publisher {
public typealias Failure = Never
public let output: Output
public init(_ output: Output) {
self.output = output
}
public func receive<S>(subscriber: S)
where S: Subscriber, S.Input == Output, S.Failure == Never {
// 创建订阅
let subscription = Subscriptions.SimpleSubscription(
subscriber: subscriber,
output: output
)
subscriber.receive(subscription: subscription)
}
}
关键点:
Just是值类型(struct)- 立即发布值并完成
- 错误类型是
Never(不会失败)
2.3 Future实现分析
public struct Future<Output, Failure: Error>: Publisher {
public typealias Output = Output
public typealias Failure = Failure
private let promise: (@escaping (Result<Output, Failure>) -> Void) -> Void
public init(_ attemptToFulfill: @escaping (@escaping (Result<Output, Failure>) -> Void) -> Void) {
self.promise = attemptToFulfill
}
public func receive<S>(subscriber: S)
where S: Subscriber, S.Input == Output, S.Failure == Failure {
let subscription = FutureSubscription(
subscriber: subscriber,
promise: promise
)
subscriber.receive(subscription: subscription)
}
}
private final class FutureSubscription<Output, Failure: Error, S: Subscriber>: Subscription
where S.Input == Output, S.Failure == Failure {
private var subscriber: S?
private let promise: (@escaping (Result<Output, Failure>) -> Void) -> Void
private var hasFulfilled = false
init(subscriber: S, promise: @escaping (@escaping (Result<Output, Failure>) -> Void) -> Void) {
self.subscriber = subscriber
self.promise = promise
}
func request(_ demand: Subscribers.Demand) {
guard !hasFulfilled else { return }
hasFulfilled = true
promise { [weak self] result in
guard let self = self, let subscriber = self.subscriber else { return }
switch result {
case .success(let value):
_ = subscriber.receive(value)
subscriber.receive(completion: .finished)
case .failure(let error):
subscriber.receive(completion: .failure(error))
}
self.subscriber = nil
}
}
func cancel() {
subscriber = nil
}
}
关键点:
Future是值类型,但内部使用引用类型FutureSubscription- 只执行一次 promise
- 使用
hasFulfilled防止重复执行
3. Subscriber协议实现
3.1 Subscriber协议定义
public protocol Subscriber: CustomCombineIdentifierConvertible {
associatedtype Input
associatedtype Failure: Error
func receive(subscription: Subscription)
func receive(_ input: Input) -> Subscribers.Demand
func receive(completion: Subscribers.Completion<Failure>)
}
3.2 Sink实现分析
public struct Sink<Input, Failure: Error>: Subscriber, Cancellable {
public typealias Input = Input
public typealias Failure = Failure
private let receiveValue: (Input) -> Void
private let receiveCompletion: (Subscribers.Completion<Failure>) -> Void
private var subscription: Subscription?
public init(
receiveCompletion: @escaping (Subscribers.Completion<Failure>) -> Void,
receiveValue: @escaping (Input) -> Void
) {
self.receiveCompletion = receiveCompletion
self.receiveValue = receiveValue
}
public func receive(subscription: Subscription) {
self.subscription = subscription
subscription.request(.unlimited) // 请求无限值
}
public func receive(_ input: Input) -> Subscribers.Demand {
receiveValue(input)
return .none // 不再请求更多值(因为已经请求了 .unlimited)
}
public func receive(completion: Subscribers.Completion<Failure>) {
receiveCompletion(completion)
subscription = nil
}
public func cancel() {
subscription?.cancel()
subscription = nil
}
}
关键点:
Sink是值类型,但内部持有Subscription引用- 默认请求
.unlimited值 - 完成或取消时清理
subscription
3.3 Assign实现分析
public struct Assign<Root, Input>: Subscriber, Cancellable {
public typealias Input = Input
public typealias Failure = Never
public let object: Root
public let keyPath: ReferenceWritableKeyPath<Root, Input>
private var subscription: Subscription?
public init(object: Root, keyPath: ReferenceWritableKeyPath<Root, Input>) {
self.object = object
self.keyPath = keyPath
}
public func receive(subscription: Subscription) {
self.subscription = subscription
subscription.request(.unlimited)
}
public func receive(_ input: Input) -> Subscribers.Demand {
object[keyPath: keyPath] = input
return .none
}
public func receive(completion: Subscribers.Completion<Never>) {
subscription = nil
}
public func cancel() {
subscription?.cancel()
subscription = nil
}
}
关键点:
- 使用
ReferenceWritableKeyPath修改对象属性 - 错误类型是
Never(不会失败)
4. Operators实现原理
4.1 Map操作符实现
extension Publisher {
public func map<T>(_ transform: @escaping (Output) -> T) -> Publishers.Map<Self, T> {
return Publishers.Map(upstream: self, transform: transform)
}
}
extension Publishers {
public struct Map<Upstream: Publisher, Output>: Publisher {
public typealias Failure = Upstream.Failure
public let upstream: Upstream
public let transform: (Upstream.Output) -> Output
public init(upstream: Upstream, transform: @escaping (Upstream.Output) -> Output) {
self.upstream = upstream
self.transform = transform
}
public func receive<S>(subscriber: S)
where S: Subscriber, S.Input == Output, S.Failure == Failure {
let mapSubscriber = MapSubscriber(
downstream: subscriber,
transform: transform
)
upstream.receive(subscriber: mapSubscriber)
}
}
private struct MapSubscriber<Upstream: Publisher, Downstream: Subscriber>: Subscriber {
typealias Input = Upstream.Output
typealias Failure = Upstream.Failure
let downstream: Downstream
let transform: (Upstream.Output) -> Downstream.Input
func receive(subscription: Subscription) {
downstream.receive(subscription: subscription)
}
func receive(_ input: Upstream.Output) -> Subscribers.Demand {
let transformed = transform(input)
return downstream.receive(transformed)
}
func receive(completion: Subscribers.Completion<Failure>) {
downstream.receive(completion: completion)
}
}
}
关键点:
Map是新的 Publisher,包装上游 Publisher- 创建中间 Subscriber 进行转换
- 保持错误类型不变
4.2 Filter操作符实现
extension Publisher {
public func filter(_ predicate: @escaping (Output) -> Bool) -> Publishers.Filter<Self> {
return Publishers.Filter(upstream: self, predicate: predicate)
}
}
extension Publishers {
public struct Filter<Upstream: Publisher>: Publisher {
public typealias Output = Upstream.Output
public typealias Failure = Upstream.Failure
public let upstream: Upstream
public let predicate: (Output) -> Bool
public init(upstream: Upstream, predicate: @escaping (Output) -> Bool) {
self.upstream = upstream
self.predicate = predicate
}
public func receive<S>(subscriber: S)
where S: Subscriber, S.Input == Output, S.Failure == Failure {
let filterSubscriber = FilterSubscriber(
downstream: subscriber,
predicate: predicate
)
upstream.receive(subscriber: filterSubscriber)
}
}
private struct FilterSubscriber<Upstream: Publisher, Downstream: Subscriber>: Subscriber {
typealias Input = Upstream.Output
typealias Failure = Upstream.Failure
let downstream: Downstream
let predicate: (Input) -> Bool
func receive(subscription: Subscription) {
downstream.receive(subscription: subscription)
}
func receive(_ input: Input) -> Subscribers.Demand {
if predicate(input) {
return downstream.receive(input)
} else {
return .max(1) // 请求下一个值
}
}
func receive(completion: Subscribers.Completion<Failure>) {
downstream.receive(completion: completion)
}
}
}
关键点:
- 不满足条件时返回
.max(1)继续请求 - 满足条件时才传递给下游
4.3 FlatMap操作符实现
extension Publisher {
public func flatMap<T, P: Publisher>(
maxPublishers: Subscribers.Demand = .unlimited,
_ transform: @escaping (Output) -> P
) -> Publishers.FlatMap<P, Self>
where P.Failure == Failure {
return Publishers.FlatMap(
upstream: self,
maxPublishers: maxPublishers,
transform: transform
)
}
}
extension Publishers {
public struct FlatMap<NewPublisher: Publisher, Upstream: Publisher>: Publisher
where NewPublisher.Failure == Upstream.Failure {
public typealias Output = NewPublisher.Output
public typealias Failure = Upstream.Failure
public let upstream: Upstream
public let maxPublishers: Subscribers.Demand
public let transform: (Upstream.Output) -> NewPublisher
public init(
upstream: Upstream,
maxPublishers: Subscribers.Demand,
transform: @escaping (Upstream.Output) -> NewPublisher
) {
self.upstream = upstream
self.maxPublishers = maxPublishers
self.transform = transform
}
public func receive<S>(subscriber: S)
where S: Subscriber, S.Input == Output, S.Failure == Failure {
let flatMapSubscriber = FlatMapSubscriber(
downstream: subscriber,
maxPublishers: maxPublishers,
transform: transform
)
upstream.receive(subscriber: flatMapSubscriber)
}
}
private final class FlatMapSubscriber<Upstream: Publisher, NewPublisher: Publisher, Downstream: Subscriber>: Subscriber {
typealias Input = Upstream.Output
typealias Failure = Upstream.Failure
private let downstream: Downstream
private let maxPublishers: Subscribers.Demand
private let transform: (Input) -> NewPublisher
private var activeSubscriptions: [AnyCancellable] = []
private var subscription: Subscription?
private var demand: Subscribers.Demand = .none
init(
downstream: Downstream,
maxPublishers: Subscribers.Demand,
transform: @escaping (Input) -> NewPublisher
) {
self.downstream = downstream
self.maxPublishers = maxPublishers
self.transform = transform
}
func receive(subscription: Subscription) {
self.subscription = subscription
downstream.receive(subscription: InnerSubscription(parent: self))
}
func receive(_ input: Input) -> Subscribers.Demand {
let newPublisher = transform(input)
let cancellable = newPublisher.sink(
receiveCompletion: { [weak self] completion in
self?.handleCompletion(completion)
},
receiveValue: { [weak self] value in
_ = self?.downstream.receive(value)
}
)
activeSubscriptions.append(cancellable)
return .none
}
func receive(completion: Subscribers.Completion<Failure>) {
// 处理完成
}
private func handleCompletion(_ completion: Subscribers.Completion<Failure>) {
// 处理内部 Publisher 完成
}
}
}
关键点:
- 管理多个内部 Publisher 订阅
- 使用
maxPublishers限制并发数 - 需要复杂的生命周期管理
5. Subjects实现原理
5.1 PassthroughSubject实现
public final class PassthroughSubject<Output, Failure: Error>: Subject {
private var subscribers: [AnySubscriber<Output, Failure>] = []
private let lock = NSRecursiveLock()
public func send(_ value: Output) {
lock.lock()
defer { lock.unlock() }
let currentSubscribers = subscribers
for subscriber in currentSubscribers {
_ = subscriber.receive(value)
}
}
public func send(completion: Subscribers.Completion<Failure>) {
lock.lock()
defer { lock.unlock() }
let currentSubscribers = subscribers
subscribers.removeAll()
for subscriber in currentSubscribers {
subscriber.receive(completion: completion)
}
}
public func send(subscription: Subscription) {
// 实现 Subject 协议
}
public func receive<S>(subscriber: S)
where S: Subscriber, S.Input == Output, S.Failure == Failure {
lock.lock()
defer { lock.unlock() }
let anySubscriber = AnySubscriber(subscriber)
subscribers.append(anySubscriber)
subscriber.receive(subscription: PassthroughSubscription(
subject: self,
subscriber: anySubscriber
))
}
private func removeSubscriber(_ subscriber: AnySubscriber<Output, Failure>) {
lock.lock()
defer { lock.unlock() }
subscribers.removeAll { $0 === subscriber }
}
}
private final class PassthroughSubscription<Output, Failure: Error>: Subscription {
weak var subject: PassthroughSubject<Output, Failure>?
let subscriber: AnySubscriber<Output, Failure>
var demand: Subscribers.Demand = .none
init(
subject: PassthroughSubject<Output, Failure>,
subscriber: AnySubscriber<Output, Failure>
) {
self.subject = subject
self.subscriber = subscriber
}
func request(_ demand: Subscribers.Demand) {
self.demand += demand
}
func cancel() {
subject?.removeSubscriber(subscriber)
subject = nil
}
}
关键点:
- 使用锁保护
subscribers数组 - 不保存当前值,新订阅者不会收到历史值
- 使用
weak引用避免循环引用
5.2 CurrentValueSubject实现
public final class CurrentValueSubject<Output, Failure: Error>: Subject {
private var subscribers: [AnySubscriber<Output, Failure>] = []
private let lock = NSRecursiveLock()
private var _value: Output
public var value: Output {
get {
lock.lock()
defer { lock.unlock() }
return _value
}
set {
send(newValue)
}
}
public init(_ value: Output) {
self._value = value
}
public func send(_ value: Output) {
lock.lock()
defer { lock.unlock() }
_value = value
let currentSubscribers = subscribers
for subscriber in currentSubscribers {
_ = subscriber.receive(value)
}
}
public func receive<S>(subscriber: S)
where S: Subscriber, S.Input == Output, S.Failure == Failure {
lock.lock()
defer { lock.unlock() }
let anySubscriber = AnySubscriber(subscriber)
subscribers.append(anySubscriber)
subscriber.receive(subscription: CurrentValueSubscription(
subject: self,
subscriber: anySubscriber
))
// 立即发送当前值
_ = subscriber.receive(_value)
}
}
关键点:
- 保存当前值
_value - 新订阅者立即收到当前值
- 使用锁保护状态
6. Schedulers实现原理
6.1 Scheduler协议
public protocol Scheduler {
associatedtype SchedulerTimeType: Strideable where SchedulerTimeType.Stride: SchedulerTimeIntervalConvertible
associatedtype SchedulerOptions
var now: SchedulerTimeType { get }
var minimumTolerance: SchedulerTimeType.Stride { get }
func schedule(options: SchedulerOptions?, _ action: @escaping () -> Void)
func schedule(
after date: SchedulerTimeType,
tolerance: SchedulerTimeType.Stride,
options: SchedulerOptions?,
_ action: @escaping () -> Void
)
func schedule(
after date: SchedulerTimeType,
interval: SchedulerTimeType.Stride,
tolerance: SchedulerTimeType.Stride,
options: SchedulerOptions?,
_ action: @escaping () -> Void
) -> Cancellable
}
6.2 DispatchQueue Scheduler实现
extension DispatchQueue: Scheduler {
public struct SchedulerOptions {
public var qos: DispatchQoS
public var flags: DispatchWorkItemFlags
public var group: DispatchGroup?
}
public struct SchedulerTimeType: Strideable {
public let dispatchTime: DispatchTime
public func distance(to other: SchedulerTimeType) -> Stride {
return Stride(dispatchTime.uptimeNanoseconds - other.dispatchTime.uptimeNanoseconds)
}
public func advanced(by n: Stride) -> SchedulerTimeType {
return SchedulerTimeType(
dispatchTime: DispatchTime(uptimeNanoseconds: dispatchTime.uptimeNanoseconds + n.magnitude)
)
}
}
public var now: SchedulerTimeType {
return SchedulerTimeType(dispatchTime: .now())
}
public var minimumTolerance: SchedulerTimeType.Stride {
return SchedulerTimeType.Stride(0)
}
public func schedule(options: SchedulerOptions?, _ action: @escaping () -> Void) {
if let options = options {
async(group: options.group, qos: options.qos, flags: options.flags, execute: action)
} else {
async(execute: action)
}
}
public func schedule(
after date: SchedulerTimeType,
tolerance: SchedulerTimeType.Stride,
options: SchedulerOptions?,
_ action: @escaping () -> Void
) {
let deadline = date.dispatchTime
if let options = options {
asyncAfter(deadline: deadline, qos: options.qos, flags: options.flags, execute: action)
} else {
asyncAfter(deadline: deadline, execute: action)
}
}
}
关键点:
- 将
DispatchQueue适配为Scheduler - 使用
DispatchTime作为时间类型 - 支持 QoS 和 DispatchGroup
7. 背压处理机制
7.1 Demand系统
extension Subscribers {
public struct Demand: Equatable, Hashable {
public static let unlimited: Demand
public static let max: (Int) -> Demand
public static let none: Demand
public static func + (lhs: Demand, rhs: Demand) -> Demand
public static func - (lhs: Demand, rhs: Demand) -> Demand
public static func += (lhs: inout Demand, rhs: Demand)
public static func -= (lhs: inout Demand, rhs: Demand)
}
}
Demand 的作用:
- 控制 Publisher 发送值的速度
- 实现背压(backpressure)
- 防止内存溢出
7.2 背压处理示例
class BackpressureSubscriber: Subscriber {
typealias Input = Int
typealias Failure = Never
private var subscription: Subscription?
private let bufferSize: Int
private var buffer: [Int] = []
init(bufferSize: Int = 10) {
self.bufferSize = bufferSize
}
func receive(subscription: Subscription) {
self.subscription = subscription
// 初始请求 bufferSize 个值
subscription.request(.max(bufferSize))
}
func receive(_ input: Int) -> Subscribers.Demand {
buffer.append(input)
// 处理缓冲区
processBuffer()
// 如果缓冲区未满,请求更多值
if buffer.count < bufferSize {
return .max(1)
} else {
return .none // 暂停请求
}
}
func receive(completion: Subscribers.Completion<Never>) {
// 处理完成
}
private func processBuffer() {
// 处理缓冲区中的数据
while !buffer.isEmpty {
let value = buffer.removeFirst()
print("处理: \(value)")
}
// 处理完后请求更多值
subscription?.request(.max(bufferSize - buffer.count))
}
}
8. 性能优化策略
8.1 值类型优化
Combine 大量使用值类型(struct),避免堆分配:
// 值类型,零成本抽象
struct Just<Output>: Publisher { }
struct Map<Upstream, Output>: Publisher { }
struct Filter<Upstream>: Publisher { }
8.2 类型擦除(eraseToAnyPublisher)
eraseToAnyPublisher() 是 Combine 中非常重要的方法,用于隐藏 Publisher 的具体类型,只暴露 Output 和 Failure 类型信息。这在需要统一返回类型、简化接口、避免类型泄露等场景中非常有用。
8.2.1 为什么需要类型擦除
问题:类型泄露(Type Leakage)
Combine 的操作符链式调用会产生复杂的嵌套类型,这些类型信息会"泄露"到函数签名中:
// ❌ 问题:类型过于复杂,难以维护
func fetchUserData() -> Publishers.Map<
Publishers.FlatMap<
Publishers.Catch<
Publishers.Map<
URLSession.DataTaskPublisher,
User
>,
Just<User>
>,
Publishers.Map<
Publishers.Debounce<
PassthroughSubject<String, Never>,
RunLoop
>,
URLSession.DataTaskPublisher
>
>,
String
> {
// 实现...
}
// ✅ 解决:使用 eraseToAnyPublisher() 简化类型
func fetchUserData() -> AnyPublisher<String, Never> {
// 实现...
return publisher.eraseToAnyPublisher()
}
类型擦除的优势:
- 简化接口:隐藏内部实现细节,只暴露必要的类型信息(Output 和 Failure)
- 统一返回类型:不同分支可以返回不同的具体 Publisher,但统一为
AnyPublisher - 避免类型泄露:防止复杂的嵌套类型污染 API
- 提高可维护性:修改内部实现不影响外部接口
8.2.2 eraseToAnyPublisher 的基本用法
基本语法:
extension Publisher {
/// 将 Publisher 转换为 AnyPublisher,隐藏具体类型
public func eraseToAnyPublisher() -> AnyPublisher<Output, Failure> {
return AnyPublisher(self)
}
}
使用示例:
// 示例1:函数返回类型简化
func loadData() -> AnyPublisher<String, Error> {
return URLSession.shared.dataTaskPublisher(for: url)
.map(\.data)
.compactMap { String(data: $0, encoding: .utf8) }
.mapError { $0 as Error }
.eraseToAnyPublisher() // 隐藏 URLSession.DataTaskPublisher 等具体类型
}
// 示例2:条件分支统一返回类型
func fetchData(useCache: Bool) -> AnyPublisher<Data, Error> {
if useCache {
return loadFromCache()
.eraseToAnyPublisher() // Just<Data, Error> -> AnyPublisher
} else {
return loadFromNetwork()
.eraseToAnyPublisher() // URLSession.DataTaskPublisher -> AnyPublisher
}
}
func loadFromCache() -> Just<Data> {
return Just(Data())
}
func loadFromNetwork() -> URLSession.DataTaskPublisher {
return URLSession.shared.dataTaskPublisher(for: url)
}
8.2.3 AnyPublisher 的内部实现
AnyPublisher 使用类型擦除模式(Type Erasure Pattern),通过包装具体 Publisher 来隐藏类型信息:
public struct AnyPublisher<Output, Failure: Error>: Publisher {
// 使用内部 Box 类型来存储具体的 Publisher
private let box: _AnyPublisherBox<Output, Failure>
/// 初始化:接受任何符合 Publisher 协议的类型
public init<P: Publisher>(_ publisher: P)
where P.Output == Output, P.Failure == Failure {
// 将具体 Publisher 包装到 Box 中
self.box = _AnyPublisherBox(publisher)
}
/// 实现 Publisher 协议:转发给内部 Box
public func receive<S>(subscriber: S)
where S: Subscriber, S.Input == Output, S.Failure == Failure {
box.receive(subscriber: subscriber)
}
}
// 内部 Box 类(简化版实现)
private class _AnyPublisherBox<Output, Failure: Error> {
private let _receive: (AnySubscriber<Output, Failure>) -> Void
init<P: Publisher>(_ publisher: P)
where P.Output == Output, P.Failure == Failure {
// 保存 publisher 的 receive 方法
self._receive = { subscriber in
publisher.receive(subscriber: subscriber)
}
}
func receive<S: Subscriber>(_ subscriber: S)
where S.Input == Output, S.Failure == Failure {
let anySubscriber = AnySubscriber(subscriber)
_receive(anySubscriber)
}
}
实现原理:
AnyPublisher是值类型(struct),但内部持有引用类型的 Box- Box 存储具体 Publisher 的
receive方法 - 通过闭包捕获和转发,实现类型擦除
8.2.4 常见使用场景
场景1:函数返回类型统一
class DataService {
// 不同方法返回不同的具体 Publisher,但统一为 AnyPublisher
func fetchUser() -> AnyPublisher<User, Error> {
return URLSession.shared.dataTaskPublisher(for: userURL)
.map(\.data)
.decode(type: User.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
func fetchPosts() -> AnyPublisher<[Post], Error> {
return URLSession.shared.dataTaskPublisher(for: postsURL)
.map(\.data)
.decode(type: [Post].self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
func fetchComments() -> AnyPublisher<[Comment], Never> {
return Just([]) // 示例:返回 Just
.eraseToAnyPublisher()
}
}
场景2:条件分支统一类型
func loadData(source: DataSource) -> AnyPublisher<Data, Error> {
switch source {
case .network:
return URLSession.shared.dataTaskPublisher(for: url)
.map(\.data)
.eraseToAnyPublisher()
case .cache:
return loadFromCache()
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
case .mock:
return Just(mockData)
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
}
}
enum DataSource {
case network
case cache
case mock
}
场景3:操作符链中的类型擦除
class SearchViewModel: ObservableObject {
@Published var searchText: String = ""
var searchResults: AnyPublisher<[String], Never> {
$searchText
.debounce(for: .milliseconds(500), scheduler: RunLoop.main)
.removeDuplicates()
.flatMap { query -> AnyPublisher<[String], Never> in
if query.isEmpty {
return Just([])
.eraseToAnyPublisher()
} else {
return self.performSearch(query: query)
.catch { _ in Just([]) }
.eraseToAnyPublisher()
}
}
.eraseToAnyPublisher() // 最终统一类型
}
private func performSearch(query: String) -> AnyPublisher<[String], Error> {
// 搜索实现
return URLSession.shared.dataTaskPublisher(for: searchURL)
.map(\.data)
.decode(type: [String].self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
}
场景4:协议中的类型擦除
protocol DataRepository {
func fetchData() -> AnyPublisher<Data, Error>
}
class NetworkRepository: DataRepository {
func fetchData() -> AnyPublisher<Data, Error> {
return URLSession.shared.dataTaskPublisher(for: url)
.map(\.data)
.eraseToAnyPublisher()
}
}
class MockRepository: DataRepository {
func fetchData() -> AnyPublisher<Data, Error> {
return Just(mockData)
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
}
}
8.2.5 何时使用 eraseToAnyPublisher
应该使用的情况:
- ✅ 函数返回类型:公开 API 需要返回 Publisher 时
- ✅ 协议要求:协议方法需要返回 Publisher 时
- ✅ 条件分支:不同分支返回不同类型,需要统一时
- ✅ 存储属性:需要存储 Publisher 但不想暴露具体类型时
- ✅ 简化接口:避免类型泄露到外部时
不应该使用的情况:
- ❌ 内部实现:只在内部使用的 Publisher,不需要擦除
- ❌ 性能敏感:类型擦除有轻微性能开销(包装和转发)
- ❌ 需要具体类型:需要访问具体 Publisher 的特殊方法时
示例对比:
// ✅ 正确:公开 API 使用类型擦除
class API {
static func fetchUser(id: Int) -> AnyPublisher<User, Error> {
return URLSession.shared.dataTaskPublisher(for: url)
.map(\.data)
.decode(type: User.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
}
// ❌ 不必要:内部实现不需要类型擦除
class ViewModel {
private func setupBinding() {
// 不需要 eraseToAnyPublisher,因为只在内部使用
$searchText
.debounce(for: .milliseconds(500), scheduler: RunLoop.main)
.sink { [weak self] text in
self?.performSearch(text)
}
.store(in: &cancellables)
}
}
8.2.6 类型擦除的性能考虑
性能开销:
- 内存开销:
AnyPublisher需要额外的 Box 包装,增加一个间接层 - 调用开销:方法调用需要通过 Box 转发,有轻微的性能损失
- 优化机会:编译器无法对擦除后的类型进行特殊优化
性能对比:
// 直接使用具体类型(性能更好)
let publisher: Publishers.Map<URLSession.DataTaskPublisher, Data> = ...
// 使用类型擦除(有轻微开销)
let publisher: AnyPublisher<Data, Error> = ...
.eraseToAnyPublisher()
建议:
- 在公开 API 中使用类型擦除,简化接口
- 在内部实现中尽量保持具体类型,获得更好的性能
- 性能敏感的场景谨慎使用
8.2.7 与其他类型擦除方法对比
Combine 提供了多种类型擦除方法:
| 方法 | 用途 | 示例 |
|---|---|---|
eraseToAnyPublisher() | 擦除 Publisher 类型 | publisher.eraseToAnyPublisher() |
AnySubscriber | 擦除 Subscriber 类型 | AnySubscriber(subscriber) |
AnyCancellable | 擦除 Cancellable 类型 | AnyCancellable(cancellable) |
统一使用模式:
// Publisher 类型擦除
let anyPublisher: AnyPublisher<String, Error> = publisher
.eraseToAnyPublisher()
// Subscriber 类型擦除(内部使用)
let anySubscriber = AnySubscriber(subscriber)
// Cancellable 类型擦除(存储订阅)
let cancellable = AnyCancellable(subscription)
8.2.8 常见错误与注意事项
错误1:忘记类型擦除导致编译错误
// ❌ 错误:类型不匹配
func fetchData() -> AnyPublisher<Data, Error> {
if condition {
return Just(data) // 类型是 Just<Data, Never>,不匹配
} else {
return URLSession.shared.dataTaskPublisher(for: url)
.map(\.data) // 类型是 Publishers.Map<...>,不匹配
}
}
// ✅ 正确:使用 eraseToAnyPublisher 统一类型
func fetchData() -> AnyPublisher<Data, Error> {
if condition {
return Just(data)
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
} else {
return URLSession.shared.dataTaskPublisher(for: url)
.map(\.data)
.eraseToAnyPublisher()
}
}
错误2:过度使用类型擦除
// ❌ 不必要:每个操作符都擦除
let publisher = [1, 2, 3].publisher
.map { $0 * 2 }
.eraseToAnyPublisher() // 不必要
.filter { $0 > 2 }
.eraseToAnyPublisher() // 不必要
.sink { print($0) }
// ✅ 正确:只在最后需要时擦除
let publisher = [1, 2, 3].publisher
.map { $0 * 2 }
.filter { $0 > 2 }
.eraseToAnyPublisher() // 只在需要统一类型时使用
错误3:类型擦除后无法访问具体方法
// ❌ 错误:AnyPublisher 没有具体 Publisher 的特殊方法
let publisher: AnyPublisher<String, Error> = ...
publisher.someSpecificMethod() // 编译错误:AnyPublisher 没有此方法
// ✅ 正确:在擦除前使用具体方法
let publisher = specificPublisher
.someSpecificMethod() // 先使用具体方法
.eraseToAnyPublisher() // 再擦除类型
8.2.9 最佳实践总结
- 公开 API 使用类型擦除:简化接口,隐藏实现细节
- 内部实现保持具体类型:获得更好的性能和类型信息
- 条件分支统一类型:使用
eraseToAnyPublisher()统一返回类型 - 避免过度使用:只在必要时使用,不要每个操作符都擦除
- 注意性能影响:性能敏感场景谨慎使用
代码示例:
// 最佳实践示例
class DataManager {
// ✅ 公开方法:使用类型擦除
func fetchData() -> AnyPublisher<Data, Error> {
return internalFetchData()
.eraseToAnyPublisher()
}
// ✅ 内部方法:保持具体类型
private func internalFetchData() -> URLSession.DataTaskPublisher {
return URLSession.shared.dataTaskPublisher(for: url)
}
// ✅ 条件分支:统一返回类型
func loadData(from source: DataSource) -> AnyPublisher<Data, Error> {
switch source {
case .network:
return networkFetch()
.eraseToAnyPublisher()
case .cache:
return cacheFetch()
.eraseToAnyPublisher()
}
}
}
通过 eraseToAnyPublisher(),我们可以在保持类型安全的同时,简化 API 接口,提高代码的可维护性和可读性。
8.3 延迟执行
使用 Deferred 延迟创建 Publisher:
let deferred = Deferred {
// 只在订阅时执行
return expensiveOperation()
}
8.4 共享订阅
使用 share() 共享 Publisher:
let shared = expensivePublisher()
.share() // 多个订阅者共享同一个 Publisher
shared.sink { } // 订阅1
shared.sink { } // 订阅2(共享执行)
📚 总结
Combine 框架的核心优势
- 类型安全:充分利用 Swift 类型系统
- 性能优化:值类型、零成本抽象
- 声明式编程:代码更简洁、易读
- 异步处理:优雅处理异步操作
- 系统集成:与 SwiftUI、Foundation 深度集成
学习建议
- 从基础开始:理解 Publisher、Subscriber、Subscription
- 实践操作符:熟悉常用操作符的使用
- 理解背压:掌握 Demand 系统
- 阅读源码:深入理解实现原理
- 实际应用:在项目中应用 Combine