本篇重点在于深刻RxSwift的部分经常使用特性,因此但愿读者在了解RxSwift官方的基本讲解与Demo以后再进行阅读。swift
RxSwift版本为5.0.0以上。缓存
在写代码的时候,咱们常常会在不少状况下建立一个Observable
:数据结构
_ = Observable<String>.create { observerOfString -> Disposable in
observerOfString.on(.next("😬"))
observerOfString.on(.completed)
return Disposables.create()
}
复制代码
又或者是在监听Observable
:闭包
let disposeBag = DisposeBag()
Observable<Int>.empty()
.subscribe { event in
print(event)
}
.disposed(by: disposeBag)
复制代码
这里老是看到是Disposables
和DisposeBag
,那么它们究竟是什么。并发
Disposables
是一个简单的结构体socket
public struct Disposables {
private init() {}
}
复制代码
经过extension生成create方法, 建立四种不一样的Disposable。性能
Disposable定义:优化
public protocol Disposable {
/// Dispose resource.
func dispose()
}
复制代码
Cancelable
, 在Disposable
的基础上添加了isDisposed
属性,便于追踪Disposable
的状态:ui
public protocol Cancelable : Disposable {
/// Was resource disposed.
var isDisposed: Bool { get }
}
复制代码
NopDisposable
, 在disposal时什么都不作。AnonymousDisposable
, 建立时传入一个public typealias DisposeAction = () -> Void
类型的闭包,在disposal时调用。BinaryDisposable
, 在建立时传入两个Disposable
类型的参数,在disposal时调用。CompositeDisposable
, 在建立时传入多个Disposable
类型的参数,在disposal时调用。除了这四种能够经过快速建立的,还有其余类型的Disposable
spa
BooleanDisposable
,主要用于追踪disposal的状态,初始化时传入Bool类型的参数,表示是否已经被Dispose。SubscriptionDisposable
,主要在Subject中使用。RefCountDisposable
,初始化时传入一个Disposable
类型的参数,如同命名,内存采用了引用计数的管理方法,调用retain方式时计数+1,调用release时计数-1,引用计数不能小于0,当等于0时,若是没有调用过dispose方法(实际上是将内部的_primaryDisposed
属性标记为true
),也不会触发dispose方法,一样若是引用计数不为0,调用dispose方法也不会触发内部的Disposable
的dispose。ScheduledDisposable
,初始化时传入一个Disposable
类型的参数与一个ImmediateSchedulerType
,指定传入的Disposable
在某个线程上执行dispose。SerialDisposable
: 能够手动替换内部的Disposable
,若是在_isDisposed
为false的状态,替换后会自动触发以前的Disposable
的dispose方法,若是为true,则直接触发替换的Disposable
的dispose方法。SingleAssignmentDisposable
:对内部的Disposable
只能设定一次,若设定屡次会报错,在没有设定的状况下触发dispose方法也会报错。DisposeBag
如同名字,是一个Bag
类型的数据结构,里面存放Disposable
的数据。
每次看到Disposable类型调用disposed(by: disposeBag)
,实际上是将Disposable放在DisposeBag中进行管理,当DisposeBag进行dispose时,对其中管理的Disposable分别dispose,可是DisposeBag不能主动调用,只能在deinit时自动释放,因此想要进行dispose操做,只能将disposeBag从新赋值,好比:
disposeBag = DisposeBag()
复制代码
Subject是在RX的某些实现中可用的桥接或代理。
经过继承了ObserverType
,能够成为一个观察者,能够经过on(_ event: Event<Element>)
发送事件。
经过继承了Observable
,能够成为一个被观察者,能够经过subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element
推送事件。
Subject都是经过Broadcasts
的方式传播事件。
在RAC中经过Signal与SignalProducer区分冷热信号的概念,RxSwift其实也有冷热信号。
冷信号是指在被观察以后才会推送事件。
热型号是指就算没有被观察,也能推送事件。
能够理解为一个主动一个被动。
这是一个比较抽象的例子:
let subject = Subject()
subject.onNext("1")
subject.subcribeNext { value in
print(value)
}
subject.onNext("2")
若是是冷信号,这时候会打印1 2,热信号则只会打印2.
复制代码
在Rx中有四种Subject。分别是BehaviorSubject
,PublishSubject
,ReplaySubject
,AsyncSubject
。
下列图标中,圆表明next信号,竖线表示complete,x表示error。
PublishSubject
就是一个热信号的Subject。
BehaviorSubject
是一个有初始值,缓存数量为1的Subject。在5.0版本以前的RxSwift中,有一个叫作Variable
的属性,在5.0以后,由于相同的特性,彻底被BehaviorSubject
取代。
ReplaySubject
是一个能够自定义缓存数量的Subject。当设定缓存数量为0时,几乎能够当作PublishSubject
使用,缓存数量为1时,能够当作一个没有初始值的BehaviorSubject
使用。
AsyncSubject
,只会在接收到Complete事件后,才会Subscribe最后一个信号,若是没有在onComplete以前没有onNext事件,或者触发了onError,则不会触发Subscribe。
简单的按钮处理,当用户名长度大于4位且密码长度大于6位时,登陆按钮才能点击:
private var disposeBag = DisposeBag()
private let nameSubject = BehaviorSubject<String>(value: "")
private let passwordSubject = BehaviorSubject<String>(value: "")
private let loginSubject = BehaviorSubject<Bool>(value: false)
private let nameTextField = UITextField()
private let passwordTextField = UITextField()
private let loginButton = UIButton()
......
//中间内容省略
......
nameTextField.rx.text.orEmpty.bind(to: nameSubject).disposed(by: disposeBag)
passwordTextField.rx.text.orEmpty.bind(to: passwordSubject).disposed(by: disposeBag)
Observable<Bool>.combineLatest(nameSubject, passwordSubject) { (name, password) -> Bool in
return name.count > 4 && password.count > 6
}.bind(to: loginButton.rx.isEnabled).disposed(by: disposeBag)
复制代码
经过某个实时持续的交互,每秒刷新UI:
private let socketSubject = ReplaySubject<String>.create(bufferSize: 1)
......
DoSomething {
socketSubject.onNext(value)
}
Observable<Int>
.interval(.seconds(1), scheduler: MainScheduler.instance)
.withLatestFrom(socketSubject)
.distinctUntilChanged()
.subscribe(onNext: { (value) in
print(value)
}).disposed(by: disposeBag)
复制代码
若是ReplaySubject
的bufferSize为1,是否与BehaviorSubject
相同?
若是ReplaySubject
的bufferSize为0,是否与PublishSubject
相同?
Schedulers是RxSwift中的调度机制。
主要运算符只有两个observeOn
以及subscribeOn
。
sequence1
.observeOn(backgroundScheduler)
.map { n in
print("This is performed on the background scheduler")
}
.observeOn(MainScheduler.instance)
.map { n in
print("This is performed on the main scheduler")
}
.subscribeOn(subscribeScheduler)
.subscribe { _ in
print("This is performed on the subscribeScheduler")
}
复制代码
经过observeOn
与subscribeOn
能够控制处理信号的线程,而且能够支持屡次切换。
CurrentThreadScheduler
(串行)。指代当前线程,若没有指定Schuduler,则默认使用。MainScheduler
(串行)。主线程,一般使用进行UI操做。在subscribeOn时更应该用作过优化的ConcurrentMainScheduler
。SerialDispatchQueueScheduler
(串行)。串行线程,主线程也是一种串行线程。ConcurrentDispatchQueueScheduler
(并发)。在初始化时也能够传入串行dispatch queue,也不会有任何问题。适用于须要在后台的工做。OperationQueueScheduler
(并发)。是NSOperationQueue
的一种抽象示例。适用与单个任务量大的任务并行处理的状况,同时但愿设定maxConcurrentOperationCount
。ConcurrentMainScheduler
?SerialDispatchQueueScheduler
,会有所优化,具体是怎么优化的?对于第二个问题,在阅读代码时,发如今observeOn
时作了单独的处理
public func observeOn(_ scheduler: ImmediateSchedulerType)
-> Observable<Element> {
if let scheduler = scheduler as? SerialDispatchQueueScheduler {
return ObserveOnSerialDispatchQueue(source: self.asObservable(), scheduler: scheduler)
}
else {
return ObserveOn(source: self.asObservable(), scheduler: scheduler)
}
}
复制代码
对于非SerialDispatchQueueScheduler
,会经过将事件以队列的方式以及加递归锁的方式存储。 而SerialDispatchQueueScheduler
,则不会,减小了性能消耗。