Swift

Combine进化之路3——Subscriber

2023-09-10  本文已影响0人  valiant_xin

和Publisher相对应的,Subscriber就是观察者模式中的Observer。

@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public protocol Subscriber<Input, Failure> : CustomCombineIdentifierConvertible {

    /// The kind of values this subscriber receives.
    associatedtype Input

    /// The kind of errors this subscriber might receive.
    ///
    /// Use `Never` if this `Subscriber` cannot receive errors.
    associatedtype Failure : Error

    /// Tells the subscriber that it has successfully subscribed to the publisher and may request items.
    ///
    /// Use the received ``Subscription`` to request items from the publisher.
    /// - Parameter subscription: A subscription that represents the connection between publisher and subscriber.
    func receive(subscription: Subscription)

    /// Tells the subscriber that the publisher has produced an element.
    ///
    /// - Parameter input: The published element.
    /// - Returns: A `Subscribers.Demand` instance indicating how many more elements the subscriber expects to receive.
    func receive(_ input: Self.Input) -> Subscribers.Demand

    /// Tells the subscriber that the publisher has completed publishing, either normally or with an error.
    ///
    /// - Parameter completion: A ``Subscribers/Completion`` case indicating whether publishing completed normally or with an error.
    func receive(completion: Subscribers.Completion<Self.Failure>)
}

Publisher在自身状态改变时,调用Subscriber的三个不同方法receive(subscription),receive(_:Input),receive(completion:)来通知Subscriber。


111.png

Publisher发出的通知有三种类型:

· Subscription:Subscriber成功订阅的消息,只会发送一次,取消订阅会调用它的cancel方法来释放资源。
· Value(Subscriber的Input,Publisher的Output):真正的数据,可能发送0次或多次。
· Completion:数据流终止的消息,包含两种类型:.finished 和 .failure(Error),最多发送一次,一旦发送完数据流就断开了,有的数据流可能永远没有终止。

大部分场景下,我们需要关心后两种消息:数据流更新和终止。

Combine内置的Subscriber有三种:
· Sink
· Assign
· Subject

Sink

Sink是非常通用的Subscriber,我们可以自由的处理数据流状态。

func subscriberFunc() {
        let oncePublisher = Just(100)
        let subscriber = Subscribers.Sink<Int, Never> {
            print("completed: \($0)")
        } receiveValue: { input in
            print("receive: \(input)")
        }
        oncePublisher.receive(subscriber: subscriber)
    }

publiser还提供了sink方法来简化整个流程

func sinktestFunc() {
        let _ = Just(100).sink {
            print("comp: \($0)")
        } receiveValue: {
            print("receive: \($0)")
        }
    }

Assign

Assign可以很方便的将接收到的值通过KeyPath设置到指定的Class上(不支持Struct),很适合将已有的程序改造成Reactive。

class People {
        let name: String
        var age: Int
        
        init(name: String, age: Int) {
            self.name = name
            self.age = age
        }
    }
    func assignTestFunc() {
        let p = People(name: "allien", age: 19)
        print("I'm \(p.name), I'm \(p.age) years old.")
        let subscriber = Subscribers.Assign(object: p, keyPath: \People.age)
        let publisher = PassthroughSubject<Int, Never>()
        publisher.subscribe(subscriber)
        publisher.send(20)
        print("I'm \(p.name), I'm \(p.age) years old.")
        publisher.send(22)
        print("I'm \(p.name), I'm \(p.age) years old.")
    }

经测试后发现,一旦publisher改变了值(调用send方法),People的age也会同步改变。

PassthroughSubject这里是Combine内置的一个Publisher。Subject是中间代理,它有时可能会作为发布者角色出现。

Combine进化之路合集

上一篇下一篇

猜你喜欢

热点阅读