hiccLoghicc log by wccHipo Log

Combine 基本概念

Publisher

public protocol Publisher {
    // 1
    associatedtype Output

    // 2
    associatedtype failure: Error

    // 4
    func receive<S>(subscriber: S) where S: Subscriber, Self.Failure == S.Failure, Self.Output == S.Input
}

extension Publisher {
    // 3
    public func subscribe<S>(_ subscriber: S) where S: Subscriber, Self.Failure == S.Failure, Self.Output == S.Input 
}
  1. Publisher 产生数据的类型
  2. Publisher可能产生错误的类型,如果能够保证一定不出错,使用Never
  3. 订阅者,可以使用subscribe(-:)来接受消息
  4. 实现subscribe(-:)需要调用receive(subscriber:)来将订阅者订阅到publisher

Subscriber

public protocol Subscriber: CustomCombineIdentifierConvertible {
    // 1
    associatedtype Input

    // 2
    associatedtype Failure: Error

    // 3
    func receive(subscription: Subscription)

    // 4
    func receive(_ input: Self.Input) -> Subscribers.Demand

    // 5
    func receive(completion: Subscribers.Completion<Self.Failure>)    
}
  1. 订阅者接收到的值得类型
  2. 订阅者可能接受到的错误信息,如果Publisher不会出错,则是Never
  3. Publisher会调用receive(subscription:)来传递 subscription
  4. Publisher调用receive(_:)来传值。
  5. Publisher调用receive(completion:),在结束或者出错时候。

Subscription

public protocol Subscription: Cancellable, CustomCombineIdentifierconvertible {
    func request(_ demand: Subscribers.Demand)
}

订阅者调用request(_:_)来告知愿意接受更多的值,从一个最大的值,到无限制。

  • subscription.request背压 backpressure mmanagement
  • Subscriber.receive(_:_)可以在每次接收到值时候调整,表示后续要接受的数量
  • Subscriber.receive(_:_)调整的值是增量的,也就是说不能是负数(否则会返回fatalError)。

自定义Subscriber

// 1 
let publisher = (1...6).publisher

// 2
final class IntSubscriber: Subscriber {
    // 3
    typealias Input = Int
    typealias Failuse = Never

    // 4
    func reveive(subscription: Subscription) {
        subscription.request(.max(3))
    }

    // 5
    func receive(_ input: Int) -> Subscribers.Demand {
        print("Recevied value", input)
        // return .unlimited
        return .none // 等于 .max(0)
    }

    // 6
    func receive(completion: Subscribers.Completion<Never>) {
        print("Received completion", completion)
    }
}

Subject

PassthroughSubject

CurrentValueSubject

// 1
var subscriptions = Set<AnyCancellable>()

// 2
let subject = CurrentValueSubject<Int, Never>(0)

// 3
subject
    .sink(receiveValue: {print($0)})
    .store(in: &subscriptions) // 4 
  • 第四步,把subscription保存在subscriptions中,通过inout参数引用而不是拷贝的方式来传递。
  • 通过subject.value的方式来获取值
  • 通过subject.value = 3赋值,或者subject.send(1)方式来发送事件
  • 注意:只能subject.send(completion: .finished)来结束事件。

类型抹除 Type erasure

// 1
let subject = PassthroughSubject<Int, Never>

// 2
let publisher = subject.eraseToAnyPublisher()

// 3
publisher
    .sink(receiveValue {print($0)})
    .store(in: &subscriptions)

// 4
subject.send(0)
  • 类型抹除后publisher, 变成了anyPublisher<Int, Never>,后续的就不会知道具体的类型和细节
  • 不再有send方法,
  • 后续写文章,可以尝试自己实现marble diagrams