叨叨两句
最近又重学RxSwift,产生了一些心得体会,本意想分享出来避免初学者走弯路,也希望获得一些大佬的指点,让自己进步能够快一些,谁知道随着学习的深入,也越来越发现这里面的趣味性,所以就变成了一篇很长的博文。
略过千篇一律的使用教程,进入我的学习世界吧。。。
正文
a.可监听序列与观察者的关系
1.可监听序列绑定观察者
2.观察者需要在可监听序列Observable的subscribe方法后面描述内容,subscribe就是观察者的内部过程。
3.观察者就是由后面的 onNext
,onError
,onCompleted
的这些闭包构建出来的一系列操作,包括观察后的响应和失败,以及观察完成。
b.观察者特征
观察者有两种:AnyObserver、Binder;Binder是UI专用观察者只负责next部分
由前面的内容我们知道,subscribe的内部描述就是观察者的整个过程。而我们已知的Rx观察者,其实是基于subscribe实现过程的封装
创建一个Int序列
let disposeBag = DisposeBag()
let number = Observable<Int>.create { (observable) -> Disposable in
observable.onNext(555)
return Disposables.create()
}
代码一
number.subscribe { (element) in
print("this is element: (element).")
} onError: { (error) in
print("this is error: (error).")
} onCompleted: {
print("this is completed.")
}.disposed(by: disposeBag)
代码二
let observer = AnyObserver<Int> { (event) in
switch event {
case .next(let element):
print("this is element: (element).")
case .error(let error):
print("this is error: (error).")
case .completed:
print("this is completed.")
}
}
number.subscribe(observer).disposed(by: disposeBag)
subscribe被封装成Observer类型;也就是说,代码一等于代码二
Binder也好理解,它具备两个特征:不处理错误,在主线程监听。写法也很简单
let observer = Binder<CGFloat>(label) { (view, number) in
view.alpha = number
}
number.subscribe(observer).disposed(by: disposeBag)
在UI观察者中,它的内部过程可以用Binder封装起来,或者用RxCocoa准备好的扩展用法,因为UI特征的观察者,没有错误事件,这种特性无疑简化了subscribe内部过程
c.序列特征
序列分为默认序列和特征序列
1.Observable默认序列
create(_ subscribe: @escaping (AnyObserver<Element>) -> Disposable) -> Observable<Element>
可以看到subscribe逃逸闭包中有一个AnyObserver,这说明什么。
说明我们需要实现的观察者类型是AnyObserver,它可能发出元素、错误和成功回调
2.以下都是特征序列
(1)single:
create(subscribe: @escaping (@escaping SingleObserver) -> Disposable) -> Single<Element>
从上面的代码,可以看到在subscribe嵌套的逃逸闭包中,有一个SingleObserver,这是一个关键字修饰的闭包
typealias SingleObserver = (SingleEvent<Element>) -> Void
最后我们得到一个SingleEvent的枚举
public enum SingleEvent<Element> {
case success(Element)
case error(Swift.Error)
}
也因此,可以根据上述的内容,得到一个结论:Single会发出一个元素,或者发出0个元素(发出一个错误),它的枚举值是SingleEvent。
所以,它的使用场景,可以用于具备成功或者错误的回调中。
(2)completable:
create(subscribe: @escaping (@escaping CompletableObserver) -> Disposable) -> PrimitiveSequence<Trait, Element>
根据上面的推断,可以很轻易的通过CompletableObserver得出CompletableEvent枚举
typealias CompletableObserver = (CompletableEvent) -> Void
public enum CompletableEvent {
case error(Swift.Error)
case completed
}
也因此,结论就是:Completable发出0个元素,并且产生一个错误事件或者完成事件,它的枚举值是CompletableEvent。
它的使用场景,可以用于关心任务的完成状态,不关心中间结果。
(3)maybe:
create(subscribe: @escaping (@escaping MaybeObserver) -> Disposable) -> PrimitiveSequence<Trait, Element>
依然参照前面的推断,可以很轻易的通过MaybeObserver得出MaybeEvent枚举
typealias MaybeObserver = (MaybeEvent<Element>) -> Void
public enum MaybeEvent<Element> {
case success(Element)
case error(Swift.Error)
case completed
}
Maybe会从三种,任意发出一种
窥探Single、Completed、Maybe
a.定义
Single
public typealias Single<Element> = PrimitiveSequence<SingleTrait, Element>
Completed
public typealias Completable = PrimitiveSequence<CompletableTrait, Swift.Never>
Maybe
public typealias Maybe<Element> = PrimitiveSequence<MaybeTrait, Element>
这样一看,他们都是基于PrimitiveSequence的结构体,这个结构体的类型是<Trait, Element>
Trait表示特征;Element姑且称它为元素。但结合上下文我推断Element是一个泛型类型的元素
public struct PrimitiveSequence<Trait, Element> {
let source: Observable<Element>
init(raw: Observable<Element>) {
self.source = raw
}
}
再往后面看,PrimitiveSequence的扩展继承于ObservableConvertibleType协议
在协议ObservableConvertibleType内部,我们看到了asObservable()方法,并在对于PrimitiveSequence的扩展中实现了这个函数方法
public protocol ObservableConvertibleType {
/// Type of elements in sequence.
associatedtype Element
@available(*, deprecated, renamed: "Element")
typealias E = Element
/// Converts `self` to `Observable` sequence.
///
/// - returns: Observable sequence that represents `self`.
func asObservable() -> Observable<Element>
}
extension PrimitiveSequence: ObservableConvertibleType {
/// Converts `self` to `Observable` sequence.
///
/// - returns: Observable sequence that represents `self`.
public func asObservable() -> Observable<Element> {
return self.source
}
}
这不就是告诉我们,Single、Completed、Maybe是可以通过asObservable(),转化为Observable序列
还有一点要声明的是Observable为Class类型,继承于ObservableType;同时它的扩展支持对特征序列的转换:
asSingle()
asMaybe()
asCompletable()
b.特征
public enum SingleTrait { }
public enum CompletableTrait { }
public enum MaybeTrait { }
以上每个序列都独立的特征,这里的特征我认为是对于PrimitiveSequenceType协议的扩展。而扩展的内容每个都不同,这是Rx中对于特征序列所封装的内部方法,如图上,就比如特征序列对于操作符的支持,而以上的扩展支持我们统称为----序列特征。
支持UI的序列
Driver:
public typealias Driver<Element> = SharedSequence<DriverSharingStrategy, Element>
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)
}
}
public enum SharingScheduler {
/// Default scheduler used in SharedSequence based traits.
public private(set) static var make: () -> SchedulerType = { MainScheduler() }
}
从源文件Driver,可以看出有两个名字Driver和DriverSharingStrategy,分别代表了什么呢?
Driver依然是一个别名,它实际上是SharedSequence(共享序列)的结构体
DriverSharingStrategy继承于SharingStrategyProtocol协议,这个协议只做两件事--控制线程调度、控制共享策略,而DriverSharingStrategy实现的内容,就是Driver其中特征的一部分
一定在主线程监听(被明确在主线程调用)
共享状态变化(控制监听同一个序列的共享状态)
ObservableConvertibleType+Driver:
基于ObservableConvertibleType扩展的协议有三个asDriver方法,它的解释是:
Converts observable sequence to `Driver` trait.
举两个例子
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)
}
public func asDriver(onErrorJustReturn: Element) -> Driver<Element> {
let source = self
.asObservable()
.observeOn(DriverSharingStrategy.scheduler)
.catchErrorJustReturn(onErrorJustReturn)
return Driver(source)
}
catchError
会在要发生onError
事件时将其拦截,并使用备用的序列替代它,再次执行操作。
catchErrorJustReturn
在获取到错误的时候返回一个备用的值。
以上例子也印证了它的另一个特征
不会产生error事件(error事件已经提前预处理了)
同时,还调用了主线程监听.observeOn(DriverSharingStrategy.scheduler)
虽然我们看到了这三个特征的的确确和Driver有关,但如何把它串联起来,看到这里就会豁然开朗:
Driver(source) = SharedSequence(source)
init(_ source: Observable<Element>) {
self._source = SharingStrategy.share(source)
}
后话说
在上面的部分,PrimitiveSequence继承于ObservableConvertibleType协议,Driver也扩展了这个协议,根据它的使用场景,可以得出它是一个基于序列转换的根协议
发掘趣味
Driver(ControlEvent、ControlProperty)
public func asDriver() -> Driver<Element> {
return self.asDriver { _ -> Driver<Element> in
#if DEBUG
rxFatalError("Somehow driver received error from a source that shouldn't fail.")
#else
return Driver.empty()
#endif
}
}
Driver(BehaviorRelay)
public func asDriver() -> Driver<Element> {
let source = self.asObservable()
.observeOn(DriverSharingStrategy.scheduler)
return SharedSequence(source)
}
d.即是序列也是观察者
最常用的是PublishSubject、BehaviorRelay。
PublishSubject只会发出订阅后产生的元素,对于订阅前产生的元素不会发出
BehaviorRelay会发出最新的元素,如果没有新元素就发出默认的元素,然后再发出新元素
subjects即是可监听序列也是观察者,在分析源码的时候我们看到subjects是Class类型,继承了:
Observable<Element>
SubjectType
ObserverType
有关SubjectType的解释,充分说明了它的定义
/// Represents an object that is both an observable sequence as well as an observer.
特殊的Subjects是RxRelay。他和 Subjects 相似,唯一的区别是不会接受 onError
或 onCompleted
这样的终止事件。因为一旦subjects接收到onError
或 onCompleted
他就无法继续工作了,也不会转发后续任何事件
PublishRelay == PublishSubject(remove onError或onCompleted);PublishSubject符合ObserverType协议,PublishRelay不符合
BehaviorRelay == BehaviorSubject(remove onError或onCompleted)
e.操作符
操作符是依托于序列的操作,帮助对原始序列进行变化和重组,也可以创建新序列 。同时,操作符使序列具备处理逻辑的能力,并通过这种能力达到我们想要的结果。
思考
关于此前学习的误区,在掌握了rxswift核心部分后,希望尽快熟悉并理解它的API各个用法帮助我在使用中游刃有余,但这是一种比较耗时的学习方法。而应该转变为"你想用它做什么,它能为你做什么",我们知道它是一个函数响应式编程思想,而它的作用其实就是在一段逻辑关系中起到一个「桥」的作用。这样理解,我们就能知道在代码的哪些地方可以使用rxswift,帮助我们提高生产效率,而我们常说的万物皆rx也要根据具体的实际情况来。
如果你和我一样是一个正在学习的初学者,不建议在公司代码中大范围的使用,很多人都想一口吃一个胖子,但这样的学习过程既疲劳也煎熬,学习成果不是一蹴而就的,多看多想总能找到正确的路线,以上是我在学习rxswift中遇到的瓶颈和反思,希望写出来对其它想学习的人能有所帮助。