RxSwift特征序列Driver的使用,以及共享附加作用与非共享附加作用的区别?

简介: RxSwift特征序列Driver的使用,以及共享附加作用与非共享附加作用的区别?


Driver的使用

Driver的特性

1. 不会产生error事件

2. 一定在MainScheduler监听(主线程监听)

3. 共享附加作用

Driver是一个精心准备的特征序列,它主要是为了简化UI层的代码,更安全的进行UI元素的绑定。


那么Dirver到底是做什么的?与其他的Observable有什么区别?接下来通过示例来分析一下;场景描述:用户输入内容,内容作为参数,在子线程发起一个请求,回到主线程订阅两次,监听响应结果;


 func testObservable() {
    let observable = textField.rx.text.skip(1).flatMap {[weak self] (text) -> Observable<String> in
        guard let `self` = self else { return Observable.just("") }//释放之后,如果还来到这self为空的时候发出一个空字符串信号
        // subscribe(on: ConcurrentDispatchQueueScheduler.init(qos: .userInitiated)) 在后台构建序列
        return self.dealwithData(inputText: text ?? "").subscribe(on: ConcurrentDispatchQueueScheduler(qos: .userInitiated))
    }
    observable.subscribe { (result) in
        Logger("第一次订阅 \(result) - 线程 - \(Thread.current)")
    }.disposed(by: disposeBag)
    observable.subscribe { (result) in
        Logger("第二次订阅 \(result) - 线程 - \(Thread.current)")
    }.disposed(by: disposeBag)
}

运行结果:

Log - 开始模拟发起请求 当前线程 - <NSThread: 0x6000027cf340>{number = 9, name = (null)}
Log - 第一次订阅 next(已经输入: 21) - 线程 - <NSThread: 0x6000027cf340>{number = 9, name = (null)}
Log - 开始模拟发起请求 当前线程 - <NSThread: 0x6000027cf340>{number = 9, name = (null)}
Log - 第二次订阅 next(已经输入: 21) - 线程 - <NSThread: 0x6000027cf340>{number = 9, name = (null)}

通过log可以发现正常情况下订阅了两次、子线程请求了两次网络,订阅的结果依然是在子线程,请求了两次意味着非共享附加作用

如果我想实现订阅两次,子线程仅请求一次网络,并把订阅的结果回到主线程该怎么做呢?我们可以这样做,通过observe(on: MainScheduler.instance)回到主线程,利用share(replay: 1, scope: .whileConnected)保证多次订阅只发起一次请求,此为共享附加作用;如代码所示:

func testMainObservable() {
    let observable = textField.rx.text.skip(1).flatMap {[weak self] (text) -> Observable<String> in
        guard let `self` = self else { return Observable.just("") }
        // subscribe(on: ConcurrentDispatchQueueScheduler.init(qos: .userInitiated)) 在后台构建序列
        return self.dealwithData(inputText: text ?? "").subscribe(on: ConcurrentDispatchQueueScheduler(qos: .userInitiated))
    }.observe(on: MainScheduler.instance).share(replay: 1, scope: .whileConnected)
    observable.subscribe { (result) in
        Logger("第一次订阅 \(result) - 线程 - \(Thread.current)")
    } onError: { (error) in
        Logger(error)//.catchAndReturn("error")
    }.disposed(by: disposeBag)
    observable.subscribe { (result) in
        Logger("第二次订阅 \(result) - 线程 - \(Thread.current)")
    } onError: { (error) in
        Logger(error)
    }.disposed(by: disposeBag)
}

运行结果:


Log - 开始模拟发起请求 当前线程 - <NSThread: 0x600003d4db00>{number = 7, name = (null)}
Log - 第一次订阅 已经输入: 21 - 线程 - <NSThread: 0x600003d08900>{number = 1, name = main}
Log - 第二次订阅 已经输入: 21 - 线程 - <NSThread: 0x600003d08900>{number = 1, name = main}

通过运行结果可以看到,上述方式已经满足了我们的需求,那么有没有更简单的方式。来实现上述需求呢?


这个时候利用driver,调用asDriver(onErrorJustReturn: "drive error"),订阅的时候不再采用subscribe而是利用drive去订阅, 其中当Observable产生error事件的时候,driver不能订阅error事件,而是以发送信号的形式,把onErrorJustReturn的值执行到订阅的回调里面去;

func testDriver() {
    let driver = textField.rx.text.asDriver().skip(1).flatMap {[weak self] (text) -> Driver<String> in
        guard let `self` = self else { return Observable.just("").asDriver(onErrorJustReturn: "drive error") }
        return self.dealwithData(inputText: text ?? "").asDriver(onErrorJustReturn: "drive error")
    }
    driver.drive { (result) in
        Logger("第一次订阅 \(result) - 线程 - \(Thread.current)")
    } onCompleted: {
        Logger("onCompleted")
    } onDisposed: {
        Logger("onDisposed")
    }.disposed(by: disposeBag)
    driver.drive { (result) in
        Logger("第二次订阅 \(result) - 线程 - \(Thread.current)")
    } onCompleted: {
        Logger("onCompleted")
    } onDisposed: {
        Logger("onDisposed")
    }.disposed(by: disposeBag)
}

运行结果:

Log - 开始模拟发起请求 当前线程 - <NSThread: 0x600001dd8a00>{number = 1, name = main}
Log - 第一次订阅 已经输入: 21 - 线程 - <NSThread: 0x600001dd8a00>{number = 1, name = main}
Log - 第二次订阅 已经输入: 21 - 线程 - <NSThread: 0x600001dd8a00>{number = 1, name = main}

通过结果可以看到满足我们的需求并和上述结果一致;最后再来看下面这一段代码,实际上会发现driver的作用和observe(on: MainScheduler.instance).catchAndReturn(-1).share(replay: 1, scope: .whileConnected)是等价的;

let observable = Observable.just(1)
observable.observe(on: MainScheduler.instance).catchAndReturn(-1).share(replay: 1, scope: .whileConnected)
//等价
observable.asDriver(onErrorJustReturn: -1)


相关文章
|
数据库
主题域、概念、逻辑、物理四种模型有什么区别与联系?
主题域、概念、逻辑、物理四种模型有什么区别与联系?
|
6月前
|
JavaScript 前端开发 Java
函数形状的定义方式在编程中可以有多种,具体取决于使用的编程语言和上下文。以下是几种常见的定义方式:
函数形状的定义方式在编程中可以有多种,具体取决于使用的编程语言和上下文。以下是几种常见的定义方式:
50 3
|
4月前
|
安全 前端开发 Java
|
6月前
|
缓存 JavaScript
计算属性和方法有什么区别?怎样选择
计算属性和方法有什么区别?怎样选择
|
7月前
|
C语言
LabVIEW局部变量和值属性节点之间的区别
LabVIEW局部变量和值属性节点之间的区别
143 0
|
7月前
|
算法 编译器 C++
【C++ 概念区分】C++ 中覆盖,重写,隐藏 三者的区别
【C++ 概念区分】C++ 中覆盖,重写,隐藏 三者的区别
204 0
|
7月前
|
存储
通俗解释:Session生成、存储与管理
通俗解释:Session生成、存储与管理
77 0
第4章 MATLAB编程基础——4.6 M文件中变量的检测与传递
第4章 MATLAB编程基础——4.6 M文件中变量的检测与传递
|
JavaScript 前端开发
vvue基础指令和基础属性
vue基础指令和基础属性
|
关系型数据库 MySQL 数据库
数据库技术知识点(一)IDEFO需求建模方法、解释实体、实体型、实体集的区别、完全函数依赖、部分函数依赖、传递函数、平凡函数依赖、非平凡函数依赖举例、超码、主码、候选码的概念与区分
数据库技术知识点(一)IDEFO需求建模方法、解释实体、实体型、实体集的区别、完全函数依赖、部分函数依赖、传递函数、平凡函数依赖、非平凡函数依赖举例、超码、主码、候选码的概念与区分
数据库技术知识点(一)IDEFO需求建模方法、解释实体、实体型、实体集的区别、完全函数依赖、部分函数依赖、传递函数、平凡函数依赖、非平凡函数依赖举例、超码、主码、候选码的概念与区分