在篇目一中,咱们简略讲述了如何运用combine
,但是其实在的运用场景相对灵活多变,因此针对不同运用场景,采取不同的运用办法,就需求咱们把握更多的运用办法,以下是几个combine
的常用办法,十分好用,主张收藏。
组合多个Publisher的成果
Publisher最常用的办法就是获取值后进行告诉回调,然后进行核算操作。单个的回调,咱们在篇目一中讲解过,这里就不多做介绍了。有些场景下,咱们需求等候两个变量都获取值后,再进行操作,比如我个人开发的满满财表,需求等候汇率跟现金都获取到再汇总核算。
针对于这个问题,一般有两种解决办法:
zip
以下是zip的运用办法:
let publisher1 = URLSession.shared.dataTaskPublisher(for: url1)
let publisher2 = URLSession.shared.dataTaskPublisher(for: url2)
Publishers.Zip(publisher1, publisher2)
.sink { completion in
// 处理完结事件
} receiveValue: { data1, data2 in
// 处理两个Publisher的成果
}
CombineLatest
以下是CombineLatest的运用办法:
let publisher1 = URLSession.shared.dataTaskPublisher(for: url1)
let publisher2 = URLSession.shared.dataTaskPublisher(for: url2)
Publishers.CombineLatest(publisher1, publisher2)
.sink { completion in
// 处理完结事件
} receiveValue: { data1, data2 in
// 处理两个Publisher的成果
}
差异
迷糊没??没错,这两个办法在运用上,一摸一样,那么该如何挑选呢?
CombineLatest:
- 当任何一个源发布者宣布新值时,将获取一切源发布者的最新值并进行组合。
- 生成的新发布者将按照最近接纳到的值来更新。
- 发布者之间的值能够不完全对应,只要至少有一个发布者有值,就能够进行组合。
Zip:
- 等候一切源发布者都宣布一个新值后,才进行组合。
- 组合的值将以元组的方式呈现,包括一切源发布者的最新值。
- 发布者之间的值必须严厉一一对应,否则组合将等候一切发布者都具有对应的值。
也就是说,如果咱们其中一个数据源改动就需求进行回调操作,那么咱们就应该挑选运用CombineLatest,如果咱们的运用场景是两个数据源的数据必须全部修正才进行回调,那么咱们就应该挑选运用Zip。
定时操作和超时处理
有些场景下,数据源的数据并非需求及时回调,这个时候咱们就需求选用延时处理,办法如下:
let publisher = ...
let timeoutInterval: TimeInterval = 5.0
publisher
.timeout(timeoutInterval, scheduler: DispatchQueue.main, options: nil) {
// 在超不时履行的闭包
}
.sink { completion in
// 处理完结事件
} receiveValue: { value in
// 处理成果值
}
在上述示例中,运用timeout
操作符设置一个超不时刻,如果在指定时刻内没有收到新的值,将履行供给的闭包。这能够用于处理网络恳求等需求设定超时的场景。
条件切换
import Combine
enum Condition {
case trueCondition
case falseCondition
}
let conditionPublisher = CurrentValueSubject<Condition, Never>(.trueCondition)
let truePublisher = Just("True Publisher")
let falsePublisher = Just("False Publisher")
conditionPublisher
.flatMap { condition -> AnyPublisher<String, Never> in
switch condition {
case .trueCondition:
return truePublisher.eraseToAnyPublisher()
case .falseCondition:
return falsePublisher.eraseToAnyPublisher()
}
}
.sink { value in
print("Received value: (value)")
}
在上述示例中,咱们运用CurrentValueSubject
作为条件发布者,并初始化为.trueCondition
。咱们界说了两个简略的Just
发布者,别离表明条件为true
和false
时的成果。
然后,咱们运用flatMap
操作符将conditionPublisher
的条件值映射到相应的发布者,并运用eraseToAnyPublisher
将成果转化为AnyPublisher
类型。这样,咱们就能够将两个不同的发布者进行组合。
最终,咱们经过sink
订阅了组合后的发布者,并在接纳到值时进行打印。
咱们能够依据需求修正条件和成果的类型,并依据详细的事务逻辑和场景界说自己的条件发布者和成果发布者。
自界说操作符
一般情况下,体系供给的combine
操作符就能够满意大部分的操作需求,但是如果在实践开发中遇到了以下场景:
- 组合多个发布者的值:当您需求将多个发布者的值进行兼并、组合或转化时,能够运用自界说操作符。例如,将两个发布者的值进行兼并、依据条件过滤值、对值进行转化等。
- 封装常用的操作序列:如果您常常运用一系列的操作符来处理发布者的值,您能够将这些操作符封装为一个自界说操作符,以便在代码中重复运用。这样能够提高代码的可读性和可维护性。
- 创建特定功用的操作符:自界说操作符允许您依据自己的需求创建特定功用的操作符。例如,如果您需求履行一些特定的数据处理、过滤、聚合或转化操作,您能够界说一个自界说操作符来满意这些需求。
- 扩展Combine结构的功用:自界说操作符是扩展Combine结构功用的强壮工具。您能够运用自界说操作符来填补Combine结构中缺少的某些操作符或功用,以满意特定的需求。
自界说操作符是Combine结构的一个十分强壮的功用,它能够帮助您依据自己的需求扩展Combine结构的功用。自界说操作符是经过完成Publisher
协议的扩展来完成的。
下面是一个简略的比如,展现了如何创建一个自界说操作符,将两个发布者的值进行兼并:
swiftCopy code
struct MergeOperator<Upstream1: Publisher, Upstream2: Publisher>: Publisher {
typealias Output = Upstream1.Output
typealias Failure = Upstream1.Failure
let upstream1: Upstream1
let upstream2: Upstream2
init(upstream1: Upstream1, upstream2: Upstream2) {
self.upstream1 = upstream1
self.upstream2 = upstream2
}
func receive<S>(subscriber: S) where S : Subscriber, Self.Failure == S.Failure, Self.Output == S.Input {
let subscription = MergeOperatorSubscription(subscriber: subscriber)
upstream1.subscribe(subscription)
upstream2.subscribe(subscription)
}
}
class MergeOperatorSubscription<SubscriberType: Subscriber>: Subscription where SubscriberType.Input == Int {
private var subscriber: SubscriberType?
init(subscriber: SubscriberType) {
self.subscriber = subscriber
}
func request(_ demand: Subscribers.Demand) {
// Do nothing
}
func cancel() {
subscriber = nil
}
func receive(_ input: Int) {
_ = subscriber?.receive(input)
}
}
extension Publisher {
func merge<Other: Publisher>(with other: Other) -> MergeOperator<Self, Other> {
return MergeOperator(upstream1: self, upstream2: other)
}
}
let publisher1 = Just(1)
let publisher2 = Just(2)
let mergedPublisher = publisher1.merge(with: publisher2)
let subscription = mergedPublisher
.sink { value in
print("Received merged value: (value)")
}
在上面的比如中,咱们首要界说了一个MergeOperator
类型,它完成了Publisher
协议。这个类型包括两个泛型参数Upstream1
和Upstream2
,别离表明要兼并的两个发布者类型。MergeOperator
类型还界说了Output
和Failure
类型,它们别离表明兼并后的发布者即将发布的值类型和错误类型。
MergeOperator
类型完成了receive(subscriber:)
办法,该办法接纳一个订阅者,并将订阅者注册到要兼并的两个发布者中。此外,MergeOperator
类型还完成了一个内部的MergeOperatorSubscription
类,它完成了Subscription
协议,它的作用是接纳来自要兼并的两个发布者的值,并将这些值转发给订阅者。
最终,咱们在Publisher
协议的扩展中完成了自界说操作符merge(with:)
,该操作符接纳一个要兼并的发布者,并将它们传递给MergeOperator
类型的结构函数。