Combine之Operator(Multiple subscribers 多重订阅)

·  阅读 802

github.com/agelessman/…

在真实的开发环境中,最常用的pipline组合为一个publisher对应一个subscriber,但也有例外,本文主要讲解一个publisher对应多个subscribers。

multicast

image.png

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收到的随机数都是一样的,但是时机不同,对于cancellable2cancellable3来说,收到的是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

image.png

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) }
复制代码
  1. 本质上,share是下边代码的极简写法:
.multicast { PassthroughSubject<(String, Int), Never>() }
复制代码
  1. shareConnectablePublisher/autoconnect()的,也就是自动连接的,不需要调用.connect
分类:
iOS
标签:
收藏成功!
已添加到「」, 点击更改