Driver提供一种简便的方法在UI层编写响应式代码,简单来说就是序列驱动应用程序,如果序列满足如下特征,就可以使用Driver
1.不会产生error事件
2.一定在主线程监听MainScheduler
3.共享状态变化shareReplayLatestWhileConnected
使用Driver的场景:
1.通过CoreData来驱动UI
2.使用一个UI元素的值(绑定)来驱动另一个UI元素的值
3.与普通的操作系统驱动程序一样,如果出现序列错误,应用程序将停止响应用户输入
4.在主线程上观察到这些元素也是必要的,因为UI元素和应用程序逻辑通常不是线程安全的
5.此外,使用构建Driver的可观察序列,它是共享状态变化
Demo功能是,当TextField输入数据时候(一个UI元素),Lab(另一个UI元素)的text和Btn(另一个UI元素)的Tittle内容发生更改.
这里解释下最基本的实现方法,dealWithData方法先将UitextField的输入的值映射成序列,通过创建序列result,然后对序列result进行订阅,在订阅到序列的逻辑中刷新UI.
dealWithData方法,将字符串转化为序列
func dealWithData(inputText:String) -> Observable<Any> {
//这里的请求网络是模拟的,并没有真的请求,只是将数据的textField的内容做了更改,实际开发中可以自行修改
print("请求网络\(Thread.current)")
return Observable<Any>.create { (ob) -> Disposable in
if inputText == "1234" {
ob.onError(NSError.init(domain: "log.error", code: 10096, userInfo: nil))
}
DispatchQueue.global().async {
print("发送之前的内容:\(Thread.current)")
ob.onNext("已经输入:\(inputText)")
ob.onCompleted()
// 子线程刷新UI会crash
// self.btn.setTitle("123", for: .normal)
}
return Disposables.create()
}
}
在viewDidLoad中来实现序列的映射
let result = tf.rx.text.skip(1)
.flatMap{[weak self](input) -> Observable<Any> in
return (self?.dealWithData(inputText:input ?? ""))!
}
在viewDidLoad中实现订阅
result.subscribe(onNext:{ (element) in
print("订阅到\(element)")
})
result.subscribe(onNext:{ (element) in
print("订阅到:\(Thread.current) --- \(element)")
})
以上代码即可实现所需的功能,但是是存在问题的。
问题1:被订阅的次数是多少,网络请求的次数就有多少,这里浪费网络请求资源和带宽
问题2.订阅到的实现是在子线程中的,如果再订阅到的时候刷新UI,代码会crash
问题3.关于自定义的错误回调,也要进行处理。即可以显示错误,但是不能让应用因错误而崩溃。
解决方案:
调用函数
.share(replay: 1, scope: .whileConnected)
这样写网络请求就只执行一次
.observeOn(MainScheduler.instance)
这样写订阅到的时候就是主线程
接下来是错误事件的处理,这样处理就会将错误处理发出来,而不是直接闪退,减少因为error而出现的闪退
.catchErrorJustReturn("检测到了error事件")
序列创建综合实现
let result = tf.rx.text.skip(1)
.flatMap{[weak self](input) -> Observable<Any> in
return (self?.dealWithData(inputText:input ?? ""))!
.observeOn(MainScheduler.instance)
.catchErrorJustReturn("检测到了error事件")
}.share(replay: 1, scope: .whileConnected)
按照上面综合实现的代码可以解决上面提到的三个问题。功能的实现到此结束。
接下来是优化写法方案:
序列的创建方案实现,将oberverable序列转化成driver类型来实现序列的创建
//可选项orEmpty
let result = tf.rx.text.orEmpty
.asDriver()
.flatMap {
return self.dealWithData(inputText: $0)
.asDriver(onErrorJustReturn: "检测到错误事件")
}
序列订阅和UI绑定
result.map{"长度\(($0 as! String).count)"}
.drive(self.lab.rx.text)
result.map{"长度\($0 as! String)"}
.drive(self.btn.rx.title())
按照driver序列的实现
代码拉取地址:
https://gitee.com/xgkp/hFunction.git
实现
图示UI
1
网友评论