特征序列:Driver
- Driver 是面对UI的封装,是
SharedSequence的别名
public typealias Driver<Element> = SharedSequence<DriverSharingStrategy, Element>
主要有以下几个特点:
- 不会产生错误序号
catchErrorJustReturn("error") - 在主线程执行
MainScheduler() - 共享状态变化
share(replay: 1, scope: .whileConnected)
让我们举个例子:
一般网络请求后的数据,我们都会绑定到UI上,下面我们来模拟一下这个情况。
TF的输入作为网络请求的数据,将数据的长度和内容分别绑定到Lable和Button上
模拟网络请求
func dealwithData(inputText:String) -> Observable<Any> {
print("请求网络了\(Thread.current)")
return Observable<Any>.create { (ob) -> Disposable in
if inputText == "10086" {
ob.onError(NSError.init(domain: "马小撂", code: 10086, userInfo: nil))
}
DispatchQueue.global().async {
print("发送之前看看:\(Thread.current)")
ob.onNext(inputText)
ob.onCompleted()
}
return Disposables.create()
}
}
UI层面的绑定
let result = inputTF.rx.text.skip(1)
.flatMap { [weak self](input) -> Observable<Any> in
return (self?.dealwithData(inputText: input ?? ""))!
}
let _ = result.map{ "长度: \(($0 as! String).count)" }.bind(to: self.textLabel.rx.text)
let _ = result.map{ $0 as! String }.bind(to: self.button.rx.title())
这段代码会存在问题
- 不能接受错误事件
- 两次订阅就会有两次请求
为了解决上面的两个问题,添加两句代码
let result = inputTF.rx.text.skip(1)
.flatMap { [weak self](input) -> Observable<Any> in
return (self?.dealwithData(inputText: input ?? ""))!
.observeOn(MainScheduler())//回到主线程
.catchErrorJustReturn("检测到错误事件")
}.share(replay: 1, scope: .whileConnected)//共享状态变化
let _ = result.map{ "长度: \(($0 as! String).count)" }.bind(to: self.textLabel.rx.text)
let _ = result.map{ $0 as! String }.bind(to: self.button.rx.title())
问题解决了,但是每次都要共享状态,回到主线程,
检测error事件,是不是可以封装一下呢?🤔
作者已经为我们想到了,提供了一个特征序列Driver
//driver
let result = inputTF.rx.text.orEmpty
.asDriver()
.flatMap {
return self.dealwithData(inputText: $0)
.asDriver(onErrorJustReturn: "检测到了错误事件")
}
let _ = result.map { "长度: \(($0 as! String).count)"}.drive(self.textLabel.rx.text)
let _ = result.map { "\($0 as! String)"}
.drive(self.button.rx.title())
这里我们需要提供一个检测error的事件,其他的交给diver。
让我们来看看diver帮我们做了什么
asDriver()这个函数,注释是这样的 ConvertsControlPropertytoDrivertrait.
public func asDriver(onErrorRecover: @escaping (_ error: Swift.Error) -> Driver<Element>) -> Driver<Element> {
let source = self
.asObservable()
.observeOn(DriverSharingStrategy.scheduler)
.catchError { error in
onErrorRecover(error).asObservable()
}
return Driver(source)
}
asDriver这个函数我们可以看见一个catchError
observeOn()和外面写的一样,应该是控制线程的,我们点进去验证以下:
DriverSharingStrategy.scheduler
public struct DriverSharingStrategy: SharingStrategyProtocol {
public static var scheduler: SchedulerType { return SharingScheduler.make() }
public static func share<Element>(_ source: Observable<Element>) -> Observable<Element> {
return source.share(replay: 1, scope: .whileConnected)
}
}
SharingScheduler.make():
public private(set) static var make: () -> SchedulerType = { MainScheduler() }
返回return Driver(source)做了什么
让我们看一下Driver的初始化,上面我们知道diver是SharedSequence的别名,所以我们来看一下SharedSequence的初始化。
init(_ source: Observable<Element>) {
self._source = SharingStrategy.share(source)
}
调用了share
public static func share<Element>(_ source: Observable<Element>) -> Observable<Element> {
return source.share(replay: 1, scope: .whileConnected)
}
又满足了共享函数
最后
DriverSharingStrategy.scheduler其实就相当于MainScheduler(),又回到我们的主线程。 而且上面的dirver在初始化的时候帮我们调用了share(replay: 1, scope: .whileConnected)我们需要的diver都帮我们在内部都帮我们调用了,之我们只需要绑定在我们的UI上就可以了,注意绑定的时候用drive而不是bind了。