在真实的开发环境中,最常用的pipline组合为一个publisher对应一个subscriber,但也有例外,本文主要讲解一个publisher对应多个subscribers。
multicast
multicast
实在是一个非常有意思的Operator,有了它,我们可以为publisher设置多个subscribers。
其实,这里边暗含了数据分享的含义,就仿佛publisher向多个subscribers分享同一份数据。在Combine中,publisher是一个struct
,大家都知道,struct
是值copy的,它不像class
,引用的都是一份数据,但是multicast
就能够实现这个神奇的功能,可以这样理解,它把publisher变成了class类型。
先看一下实现上图的代码:
let publisher = ["First", "Second", "Third"]
.publisher
.map {
($0, Int.random(in: 1...100))
}
.print("Random")
.multicast {
PassthroughSubject<(String, Int), Never>()
}
cancellable1 = publisher.sink { print($0) }
cancellable2 = publisher.sink { print($0) }
cancellable3 = publisher.sink { print($0) }
publisher.connect()
复制代码
打印结果如下:
Random: receive value: (("First", 22))
("First", 22)
("First", 22)
("First", 22)
Random: receive value: (("Second", 82))
("Second", 82)
("Second", 82)
("Second", 82)
Random: receive value: (("Third", 59))
("Third", 59)
("Third", 59)
("Third", 59)
复制代码
这个例子也是来源于官方,一共发送了3组随机的整数,对照着示意图和代码,我们能够看出,3个subscribers是同时收到随机数的,相反,如果我们去掉.multicast
的代码会怎么呢?
let publisher = ["First", "Second", "Third"]
.publisher
.map {
($0, Int.random(in: 1...100))
}
.print("Random")
cancellable1 = publisher.sink { print($0) }
cancellable2 = publisher.sink { print($0) }
cancellable3 = publisher.sink { print($0) }
复制代码
Random: receive value: (("First", 27))
cancellable1: ("First", 27)
Random: receive value: (("Second", 23))
cancellable1: ("Second", 23)
Random: receive value: (("Third", 75))
cancellable1: ("Third", 75)
Random: receive finished
Random: receive subscription: ([("First", 27), ("Second", 23), ("Third", 75)])
Random: request unlimited
Random: receive value: (("First", 27))
cancellable2: ("First", 27)
Random: receive value: (("Second", 23))
cancellable2: ("Second", 23)
Random: receive value: (("Third", 75))
cancellable2: ("Third", 75)
Random: receive finished
Random: receive subscription: ([("First", 27), ("Second", 23), ("Third", 75)])
Random: request unlimited
Random: receive value: (("First", 27))
cancellable3: ("First", 27)
Random: receive value: (("Second", 23))
cancellable3: ("Second", 23)
Random: receive value: (("Third", 75))
cancellable3: ("Third", 75)
Random: receive finished
复制代码
通过打印可以看出,最终,这3个subscribers收到的随机数都是一样的,但是时机不同,对于cancellable2
和cancellable3
来说,收到的是publisher的数据拷贝。
相信细心的读者应该已经发现了,去掉了.multicast
的代码还少了一行:
publisher.connect()
复制代码
当使用了.multicast
后,publisher不仅仅变成了class类型,而且变成了ConnectablePublisher
,只有主动调用.connect()
才能开启pipline。
multicast有两种使用方法:
public func multicast<S>(_ createSubject: @escaping () -> S) -> Publishers.Multicast<Self, S> where S : Subject, Self.Failure == S.Failure, Self.Output == S.Output
复制代码
public func multicast<S>(subject: S) -> Publishers.Multicast<Self, S> where S : Subject, Self.Failure == S.Failure, Self.Output == S.Output
复制代码
分别是:
- 闭包参数,返回一个Subject
- 直接返回Subject
.multicast { PassthroughSubject<(String, Int), Never>() }
.multicast(subject: PassthroughSubject<(String, Int), Never>())
复制代码
share
share
的功能和multicast
几乎一摸一样,可以把share
理解成multicast
的极简写法。主要用法可以参考上边multicast
小节的讲解内容,这里就不在重复了,下边主要说明一下两者的不同之处。
let publisher = ["First", "Second", "Third"]
.publisher
.map {
($0, Int.random(in: 1...100))
}
.print("Random")
.share()
cancellable1 = publisher.sink { print($0) }
cancellable2 = publisher.sink { print($0) }
cancellable3 = publisher.sink { print($0) }
复制代码
- 本质上,
share
是下边代码的极简写法:
.multicast { PassthroughSubject<(String, Int), Never>() }
复制代码
share
是ConnectablePublisher/autoconnect()
的,也就是自动连接的,不需要调用.connect
。