这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战
前言
抱歉,最近忙于公司的项目,焦头烂额,所以更新稍微慢了一点。
后面有时间,会把公司项目的一些问题总结一下和大家分享一下。
那么我们接上一节的内容的继续,上一节我将现实中的流水线
和Observable(序列)做了比较,通过流水线的工作情况,我们可能更加清晰的认识到序列的工作原理,对于序列的元素发出(next)、异常(error)、完成(completed)都有了认识。
这一节,我们详细介绍一下特征序列
,也就是Observable的特异化序列。
特征序列
RxSwift的特征序列分为下面6种:
- Single
- Completable
- Maybe
- Driver
- Signal
- ControlEvent
我会详细介绍与类比Single与Observable的不同,其他的特征序列也就是一举反三的事情了。那么我们开始吧。
Single
Single 是
Observable
的另外一个版本。不像Observable
可以发出多个元素,它要么只能发出一个元素,要么产生一个error
事件。
Single与Observable的两个不同点:
-
Observable中可以发出多个元素,而Single只能发出一个元素,你可以理解为:Observable流水线上面一次可以传输多个物品,而Single流水线上面一次只能传输一个物品。
-
Observable可以处理的实现有
3个
:next、error、completed,而Single只能处理2个
事件:success和error。-
Single的success事件其实就可以理解为Observable的next事件,由于Single一次只传递一个元素完成了,就不会next,而是success啦。
-
回想一下Single中的success和error,是不是和Swift.Result类型的机制极其相似?
SingleEvent
的枚举:public enum SingleEvent<Element> { case success(Element) case error(Swift.Error) } 复制代码
然后再回想一下,目前主流的网络请求库Alamofire、网络请求封装库Moya、图片请求库Kingfisher,它们的数据请求返回的类型,是什么?
Swift.Result类型!
所以Single也天然的用于异步请求返回中,因为一个网络请求一般只会返回一个结果,要么返回成功,要么返回失败,虽然在成功和失败还有很多需要细化,但是主体不会改变。
RxMoya也是如此封装的。
public extension Reactive where Base: MoyaProviderType { /// Designated request-making method. /// /// - Parameters: /// - token: Entity, which provides specifications necessary for a `MoyaProvider`. /// - callbackQueue: Callback queue. If nil - queue from provider initializer will be used. /// - Returns: Single response object. func request(_ token: Base.Target, callbackQueue: DispatchQueue? = nil) -> Single<Response> { return Single.create { [weak base] single in let cancellableToken = base?.request(token, callbackQueue: callbackQueue, progress: nil) { result in switch result { case let .success(response): single(.success(response)) case let .failure(error): single(.error(error)) } } return Disposables.create { cancellableToken?.cancel() } } } } 复制代码
-
有关Single的本质,也可以通过下面的代码一目了然:
- 首先它是PrimitiveSequence是一个简略写法:
public typealias Single<Element> = PrimitiveSequence<SingleTrait, Element>
复制代码
- PrimitiveSequence本质上还是封装了Observable,我们从定义与初始化方法中就可以看出:
/// Observable sequences containing 0 or 1 element.
public struct PrimitiveSequence<Trait, Element> {
let source: Observable<Element>
init(raw: Observable<Element>) {
self.source = raw
}
}
复制代码
Completable和Maybe
Completable 是
Observable
的另外一个版本。不像Observable
可以发出多个元素,它要么只能产生一个completed
事件,要么产生一个error
事件。
Maybe 是
Observable
的另外一个版本。它介于 Single 和 Completable 之间,它要么只能发出一个元素,要么产生一个completed
事件,要么产生一个error
事件。
通过上面的描述,我们可以清晰的看到,Completable、Maybe和Single是多么相似:
-
它们都只能产生一个单一的事件。
-
Single是success或者error。
Single在上面已经给出了代码,这里就不重复了。
-
Completable是completed或者error。
public enum CompletableEvent { /// Sequence terminated with an error. (underlying observable sequence emits: `.error(Error)`) case error(Swift.Error) /// Sequence completed successfully. case completed } 复制代码
- Maybe是success或者error或者completed。
public enum MaybeEvent<Element> { /// One and only sequence element is produced. (underlying observable sequence emits: `.next(Element)`, `.completed`) case success(Element) /// Sequence terminated with an error. (underlying observable sequence emits: `.error(Error)`) case error(Swift.Error) /// Sequence completed successfully. case completed } 复制代码
-
-
它们只是产生事件的
类型
不同! -
它们甚至在源码中别名最后指向的类型都是
PrimitiveSequence
,只是在后面遵守不同的协议导致了特异化。
Completable:
/// Sequence containing 0 elements
public enum CompletableTrait { }
/// Represents a push style sequence containing 0 elements.
public typealias Completable = PrimitiveSequence<CompletableTrait, Swift.Never>
复制代码
Maybe:
/// Sequence containing 0 or 1 elements
public enum MaybeTrait { }
/// Represents a push style sequence containing 0 or 1 element.
public typealias Maybe<Element> = PrimitiveSequence<MaybeTrait, Element>
复制代码
Drive、Signal、ControlEvent
Driver(司机?) 是一个精心准备的特征序列。它主要是为了简化 UI 层的代码。不过如果你遇到的序列具有以下特征,你也可以使用它:
- 不会产生
error
事件- 一定在
MainScheduler
监听(主线程监听)- 共享附加作用
Signal 和 Driver 相似,唯一的区别是,Driver会对新观察者回放(重新发送)上一个元素,而 Signal 不会对新观察者回放上一个元素。
有如下特性:
- 不会产生
error
事件- 一定在
MainScheduler
监听(主线程监听)- 共享附加作用
ControlEvent 专门用于描述 UI 控件所产生的事件,它具有以下特征:
- 不会产生
error
事件- 一定在
MainScheduler
订阅(主线程订阅)- 一定在
MainScheduler
监听(主线程监听)- 共享附加作用
这里将Drive、Signal、ControlEvent序列放在一起说,看看他们的特性的共同点就知道了:
-
不会产生
error
事件。 -
一定在
MainScheduler
监听(主线程监听)。 -
共享附加作用。
以上种种的特征都说明这些序列非常适合用于驱动UI:
-
一个UI交互时间不会出现error(除非你的触摸屏坏了,这个硬件损坏,也不是软件的问题),
-
主线程监听,记得之前写代码的原则吗?一般刷新UI的代码,都需要回到主线程中完成。
-
至于这个共享附加作用,你可以理解为同一个页面产生的事件,所有的监听者都共享序列事件,而不用一次又一次的反复,这个好难说明呀,直接上官方的例子吧:
let observable: Observable<Teacher> = API.teacher(teacherId: 1)
let shareSideEffects: Driver<Teacher> = observable.asDriver(onErrorDriveWith: .empty())
let observer0: (Teacher) -> () = ...
let observer1: (Teacher) -> () = ...
shareSideEffects.drive(onNext: observer0)
shareSideEffects.drive(onNext: observer1) // 第二次订阅
复制代码
如果一个序列共享附加作用,那在第二次订阅时,不会重新发起网络请求,而是共享第一次网络请求。
当然Drive、Signal、ControlEvent序列也有不同的地方啦,不然不会划分为3种序列。
ControlEvent序列在它们之中最为简单,你可以认为所以UIControl产生的事件、还有其他UI控件(UIBarButtonItem、UIGestureRecognizer)产生的事件等。
而Driver与Signal序列在差异性上主要在于Driver会对新观察者回放(重新发送)上一个元素,而 Signal 不会对新观察者回放上一个元素:
你可以这么理解:
-
Driver发出了元素,A对它进行订阅,那么A会接受到Driver发出的元素,然后B也对它进行了订阅,那么B也会接受到Driver发出的元素。
-
Signal发出了元素,A对它进行订阅,那么A会接受到Signal发出的元素,然后B也对它进行了订阅,那么B也不会接受到Signal发出的元素。
从单词的意思上也可以这么理解:
Driver是一个持续的过程,Driver就是开车嘛,路过的风景都会积累,所以A、B都会接受到Driver发出的元素。
Signal是一个信号,是一个脉冲,Signal是一个瞬间的事情,流星雨只能在定时定点的位置才能看到,A及时赶到,所以看到了流星雨,B来晚了,流星雨错过,肯定看不到了嘛。
一般情况下状态序列我们会选用 Driver] 这个类型,事件序列我们会选用 Signal 这个类型。
需要注意的是Driver和Signal也同一个类的不同别名的表现形式:
public typealias Driver<Element> = SharedSequence<DriverSharingStrategy, Element>
复制代码
public typealias Signal<Element> = SharedSequence<SignalSharingStrategy, Element>
复制代码
总结
本节主要讲解了由Observable生成的特征序列。
我们又可以细分为两大块:
由PrimitiveSequence特异化的Single、Completable和Maybe这三种序列,它们每次只能发出一个元素,它们的差异只是事件的类型不同罢了。其中Single很多时候都用于异步网络请求的封装。
由SharedSequence特异化的Driver、Signal序列,以及专门用于表示UI控件产生事件的ControlEvent序列,它们多用于UI驱动。
下一节预告
聊完了Observable,接下来我会讲解Observer,以及更常用的Observable & Observer。
参考文档
RxSwift编写wanandroid客户端现已开源
目前RxSwift编写wanandroid客户端已经开源了——项目链接。
我进行了一轮CodeReview,并增加了一些小功能:
-
添加了iOS的黑暗模式适配
-
上拉加载更多使用了无感知功能
-
MBProgressHUD替换为SVProgressHUD
记得给个star喔!
附上一张效果图片: