02-研究优秀开源框架@响应式编程@iOS | Combine框架:源码解析

0 阅读9分钟

二、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)),不关心具体类型。
  • 实现层:所有 JustMapFilterSink 等具体类型都遵循上述协议,并通过「包装上游 + 向下游转发」组成链条。
  • 调度层:由 Scheduler 协议抽象(如 DispatchQueueRunLoop),操作符在需要时把回调投递到指定调度器执行,从而控制线程与时机。

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 的具体类型,只暴露 OutputFailure 类型信息。这在需要统一返回类型、简化接口、避免类型泄露等场景中非常有用。

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()
}

类型擦除的优势:

  1. 简化接口:隐藏内部实现细节,只暴露必要的类型信息(Output 和 Failure)
  2. 统一返回类型:不同分支可以返回不同的具体 Publisher,但统一为 AnyPublisher
  3. 避免类型泄露:防止复杂的嵌套类型污染 API
  4. 提高可维护性:修改内部实现不影响外部接口
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

应该使用的情况:

  1. 函数返回类型:公开 API 需要返回 Publisher 时
  2. 协议要求:协议方法需要返回 Publisher 时
  3. 条件分支:不同分支返回不同类型,需要统一时
  4. 存储属性:需要存储 Publisher 但不想暴露具体类型时
  5. 简化接口:避免类型泄露到外部时

不应该使用的情况:

  1. 内部实现:只在内部使用的 Publisher,不需要擦除
  2. 性能敏感:类型擦除有轻微性能开销(包装和转发)
  3. 需要具体类型:需要访问具体 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 类型擦除的性能考虑

性能开销:

  1. 内存开销AnyPublisher 需要额外的 Box 包装,增加一个间接层
  2. 调用开销:方法调用需要通过 Box 转发,有轻微的性能损失
  3. 优化机会:编译器无法对擦除后的类型进行特殊优化

性能对比:

// 直接使用具体类型(性能更好)
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 最佳实践总结
  1. 公开 API 使用类型擦除:简化接口,隐藏实现细节
  2. 内部实现保持具体类型:获得更好的性能和类型信息
  3. 条件分支统一类型:使用 eraseToAnyPublisher() 统一返回类型
  4. 避免过度使用:只在必要时使用,不要每个操作符都擦除
  5. 注意性能影响:性能敏感场景谨慎使用

代码示例:

// 最佳实践示例
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 框架的核心优势

  1. 类型安全:充分利用 Swift 类型系统
  2. 性能优化:值类型、零成本抽象
  3. 声明式编程:代码更简洁、易读
  4. 异步处理:优雅处理异步操作
  5. 系统集成:与 SwiftUI、Foundation 深度集成

学习建议

  1. 从基础开始:理解 Publisher、Subscriber、Subscription
  2. 实践操作符:熟悉常用操作符的使用
  3. 理解背压:掌握 Demand 系统
  4. 阅读源码:深入理解实现原理
  5. 实际应用:在项目中应用 Combine