(十)RxSwift之连接操作符(connection)

705 阅读2分钟
  • 可连接的序列和一般序列不同在于:有订阅时不会立刻开始发送事件消息,只有当调用 connect() 之后才会开始发送值。
  • 可连接的序列可以让所有的订阅者订阅后,才开始发出事件消息,从而保证我们想要的所有订阅者都能接收到事件消息。
操作符 描述
publish & connect $1
replay $1
multicast $1
refCount $1
share $1
 /// 延迟函数
func delay(_ delay: Double, closure: @escaping () -> Void) {
    DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
        closure()
    }
}
  • 普通序列样式
let interval = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)

interval.subscribe(onNext: { print("订阅:1,事件:\($0)") })
    .disposed(by: self.disposeBag)

delay(3) {
    interval.subscribe(onNext: { print("订阅:2,事件:\($0)") })
    .disposed(by: self.disposeBag)
}

delay(10) {
    self.disposeBag = DisposeBag()
}
//输出:
订阅:1,事件:0
订阅:1,事件:1
订阅:1,事件:2
订阅:1,事件:3
订阅:2,事件:0
订阅:1,事件:4
订阅:2,事件:1
订阅:1,事件:5
订阅:2,事件:2
订阅:1,事件:6
订阅:2,事件:3
订阅:1,事件:7
订阅:2,事件:4
订阅:1,事件:8
订阅:2,事件:5
订阅:1,事件:9

发现有一个问题:在延时3s之后订阅的Subscription: 2的计数并没有和Subscription: 1一致,而是又从0开始了,如果想共享,怎么办?

  • publish & connect

1)publish: 将 Observable 转换为可被连接的 Observable

2)connect: 通知 ConnectableObservable 可以开始发出元素了

3)publish: 将源可观察序列转换为可连接序列 共享一个Observable的事件序列,避免创建多个Observable sequence。

4)注意:需要调用connect之后才会开始发送事件

示例:

let interval = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance).publish()

interval.subscribe(onNext: { print("订阅:1,事件:\($0)") })
    .disposed(by: disposeBag)

delay(2) {
    _ = interval.connect()
}
delay(4) {
    interval.subscribe(onNext: { print("订阅:2,事件:\($0)") }).disposed(by: self.disposeBag)
}
delay(6) {
    interval.subscribe(onNext: { print("订阅:3, 事件: \($0)") })
        .disposed(by: self.disposeBag)
}
delay(10) {
    self.disposeBag = DisposeBag()
}
输出:
订阅:1,事件:0
订阅:1,事件:1
订阅:2,事件:1
订阅:1,事件:2
订阅:2,事件:2
订阅:1,事件:3
订阅:2,事件:3
订阅:3, 事件: 3
订阅:1,事件:4
订阅:2,事件:4
订阅:3, 事件: 4
订阅:1,事件:5
订阅:2,事件:5
订阅:3, 事件: 5
订阅:1,事件:6
订阅:2,事件:6
订阅:3, 事件: 6
  • replay

1)将源可观察序列转换为可连接的序列,并将向每个新订阅服务器重放以前排放的缓冲大小

2)首先拥有和publish一样的能力,共享 Observable sequence, 其次使用replay还需要我们传入一个参数(buffer size)来缓存已发送的事件,当有新的订阅者订阅了,会把缓存的事件发送给新的订阅者

示例:

let interval = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance).replay(5)

interval.subscribe(onNext: { print(Date.time, "订阅:1,事件:\($0)")}).disposed(by: disposeBag)

delay(2) { _ = interval.connect() }

delay(4) {
    interval.subscribe(onNext: { print(Date.time,"订阅:2,事件:\($0)") })
        .disposed(by: self.disposeBag)
}
delay(8) {
    interval.subscribe(onNext: { print(Date.time,"订阅: 3, 事件: \($0)") })
        .disposed(by: self.disposeBag)
}
delay(10, closure: {
    self.disposeBag = DisposeBag()
})
//输出:
2019-10-25 19-12-25 订阅:1,事件:0
2019-10-25 19-12-26 订阅:2,事件:0
2019-10-25 19-12-26 订阅:1,事件:1
2019-10-25 19-12-26 订阅:2,事件:1
2019-10-25 19-12-27 订阅:1,事件:2
2019-10-25 19-12-27 订阅:2,事件:2
2019-10-25 19-12-28 订阅:1,事件:3
2019-10-25 19-12-28 订阅:2,事件:3
2019-10-25 19-12-29 订阅:1,事件:4
2019-10-25 19-12-29 订阅:2,事件:4
2019-10-25 19-12-30 订阅: 3, 事件: 0
2019-10-25 19-12-30 订阅: 3, 事件: 1
2019-10-25 19-12-30 订阅: 3, 事件: 2
2019-10-25 19-12-30 订阅: 3, 事件: 3
2019-10-25 19-12-30 订阅: 3, 事件: 4
2019-10-25 19-12-30 订阅:1,事件:5
2019-10-25 19-12-30 订阅:2,事件:5
2019-10-25 19-12-30 订阅: 3, 事件: 5
2019-10-25 19-12-31 订阅:1,事件:6
2019-10-25 19-12-31 订阅:2,事件:6
2019-10-25 19-12-31 订阅: 3, 事件: 6
  • multicast

将源可观察序列转换为可连接序列,并通过指定的主题广播其发射。

let netOB = Observable<Any>.create { (observer) -> Disposable in
    sleep(2)//模拟网络延迟
    print("我开始请求网络了")
    observer.onNext("请求到的网络数据")
    observer.onNext("请求到的本地")
    observer.onCompleted()
    return Disposables.create {
        print("销毁回调了")
    }
}.publish()

netOB.subscribe(onNext: { (anything) in
    print("订阅1:",anything)
})
.disposed(by: disposeBag)

// 我们有时候不止一次网络订阅,因为有时候我们的数据可能用在不同的额地方
// 所以在订阅一次 会出现什么问题?

netOB.subscribe(onNext: { (anything) in
    print("订阅2:",anything)
})
    .disposed(by: disposeBag)

_ = netOB.connect()
输出:
我开始请求网络了
订阅1: 请求到的网络数据
订阅2: 请求到的网络数据
订阅1: 请求到的本地
订阅2: 请求到的本地
销毁回调了
  • refCount

1)操作符将自动连接和断开可被连接的 Observable

2)它将可被连接的 Observable 转换为普通 Observable。当第一个观察者对它订阅时,那么底层的 Observable 将被连接。当最后一个观察者离开时,那么底层的 Observable 将被断开连接

示例:

//每隔1秒钟发送1个事件
let interval = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
    .publish()
    .refCount()
 
//第一个订阅者(立刻开始订阅)
_ = interval
    .subscribe(onNext: { print("订阅1: \($0)") })
    .disposed(by: disposeBag)
 
//第二个订阅者(延迟5秒开始订阅)
delay(5) {
    _ = interval
        .subscribe(onNext: { print("订阅2: \($0)") })
        .disposed(by: self.disposeBag)
}

delay(10, closure: {
    self.disposeBag = DisposeBag()
})
//输出:
订阅1: 0
订阅1: 1
订阅1: 2
订阅1: 3
订阅1: 4
订阅1: 5
订阅2: 5
订阅1: 6
订阅2: 6
订阅1: 7
订阅2: 7
订阅1: 8
订阅2: 8
订阅1: 9
订阅2: 9
  • share(relay:)

1)该操作符将使得观察者共享源 Observable,并且缓存最新的 n 个元素,将这些元素直接发送给新的观察者。

2)简单来说 shareReplay 就是 replay 和 refCount 的组合。 示例:

//每隔1秒钟发送1个事件
let interval = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
    .share(replay: 5)
 
//第一个订阅者(立刻开始订阅)
_ = interval
    .subscribe(onNext: { print("订阅1: \($0)") })
    .disposed(by: disposeBag)
 
//第二个订阅者(延迟5秒开始订阅)
delay(5) {
    _ = interval
        .subscribe(onNext: { print("订阅2: \($0)") })
        .disposed(by: self.disposeBag)
}

delay(10, closure: {
    self.disposeBag = DisposeBag()
})
输出:
订阅1: 0
订阅1: 1
订阅1: 2
订阅1: 3
订阅1: 4
订阅2: 0
订阅2: 1
订阅2: 2
订阅2: 3
订阅2: 4
订阅1: 5
订阅2: 5
订阅1: 6
订阅2: 6
订阅1: 7
订阅2: 7
订阅1: 8
订阅2: 8
订阅1: 9
订阅2: 9