我正在参加「启航计划」
sink
sink
担任订阅Publisher,并回来一个AnyCancellabel
。
完好签名:
public func sink(receiveCompletion: @escaping ((Subscribers.Completion<Self.Failure>) -> Void), receiveValue: @escaping ((Self.Output) -> Void)) -> AnyCancellable
它接受两个闭包回调做为参数,receiveCompletion
在发布完毕事情时被调用,receiveValue
在发布值时被调用。
来自喵神《SwiftUI和Combine编程》中的发布-订阅流程图:
在运用 sink
完成订阅时,会创立一个特殊的 Subscriber 类型 Subscribers.Sink,并被纳入上面的流程中。它会主动声明想要接纳无限多个新值,并订阅相应的 Publisher 目标。接下来,Publisher 会将新的值和完毕事情作为参数传递给 sink
传入的两个闭包,从而将响应式的事情流转化为普通的指令操作。
Backpressure(背压)
Subscriber 能够在订阅初期经过 Subscription.request 或许经过 Subscriber.receive 回来特定的 Subscribers.Demand 值来指定能够处理的值的个数。这种背压机制 (Backpressure),能够让咱们指定适宜的背压战略,来控制可接纳的值的上限,防止呈现上游的发布速度超过下游消费速度的问题。
assign
Combine内建的另一个Subscriber便是assign
,它能够用来将 Publisher 的输出值经过 key path 绑定到一个目标的特点上去。
运用assign
时有几点需求留意的当地:
-
只要 class 上用 var 声明的特点才能够经过 assign 来直接赋值
-
上游 Publisher 的 Failure 的类型有必要是 Never。如果上游 Publisher 可能会发生过错,有必要先对它进行处理,比方运用
replaceError
或许catch
来把过错在绑定之前就处理掉。 -
在中心概念 中已经有过说明,运用
assign(to:on:)
并存储生成的 AnyCancellable,可能会引起引证循环,所以请尽量运用assign(to:)
来代替assign(to:on:)
引证同享
一个Publisher可能会有多个Subscriber,如果这个Publisher是一个网络恳求的话,因为 dataTaskPublisher
是Struct,遵从值语义,屡次订阅会复制多份,每一份都是一个新的Publisher,而这会造成屡次恳求,这是很浪费资源的。
解决上面问题的方法便是运用share()
来同享Publisher。share()
操作会把本来的Publisher包装到class内,对它的进一步变形也会适用于引证语义。
Cancellable & AnyCancellable
运用sink
或许assign
订阅Publisher时,会回来一个类型为AnyCancellable
类型的值;而Timer在执行connect()
操作后得到的是一个遵从Cancellable
协议的值。
对于 Cancellable 来说,需求在适宜的时候主动调用 cancel()
方法来结束。如果在没有调用 cancel()
的情况下就将 connect
的回来值忽略或许释放掉,那么Timer会一向计时,永远不会被终结掉。所以对于需求connect
的Publisher,需求显式的调用cancel()
来完毕事情。
AnyCancellable 是一个 class,它能够对本身的生命周期进行办理。在 AnyCancellable 被释放时,它对应的订阅操作也会中止。
在使用中,咱们会在实例当中创立一个Set<AnyCancellable>
存储特点,并将sink
或许assign
回来的AnyCancellable存储其中。这样,当该实例 deinit
时,AnyCancellable 的 deinit
也会触发,并主动释放资源。这跟 RxSwift 中的 DisposeBag
很类似。
参考
王巍 《SwiftUI和Combine编程》