RXSwift 实战从无到有的swift

RxSwift学习笔记

2017-08-22  本文已影响193人  L_Zephyr

最近在学习RxSwift相关的内容,在这里记录一些基本的知识点,以便今后查阅。

Observable

在RxSwift中,最关键的一个概念是可观察序列(Observable Sequence),它相当于Swift中的序列(Sequence),可观察序列中的每个元素都是一个事件,我们知道Swift的序列中可以包含任意多个元素,类似的,可观察序列会不断产生新的事件直到发生错误或正常结束为止。订阅者(Observer)通过订阅(subscribe)一个可观察队列来接收序列所产生的新事件,只有在有观察者的情况下序列才可以发送事件。

例如,使用of操作创建一个可观察序列:

let seq = Observable.of(1, 2, 3) 

of是一种用来创建Observable的简便操作,在上面的代码中创建了一个类型为Observable<Int>的Observable,里面包含了三个元素:1,2,3。

来看看Observable中都提供了哪些操作,可观察序列是一个实现了ObservableType协议的类型,ObservableType协议的定义非常简单:

protocol ObservableType : ObservableConvertibleType {
    associatedtype E
    func subscribe<O: ObserverType>(_ observer: O) -> Disposable where O.E == E
}

其中E是一个关联类型,表示序列中元素的类型,除此之外协议只定义了一个方法:subscribe,用于向可观察序列添加一个观察者(ObserverType类型):

// 接收闭包的subscribe函数是通过协议扩展提供的简便方法
seq.subscribe { (event) in
    print(event)
}

subscribe相当于Swift序列中的遍历操作(makeIterator),如上,向seq序列添加一个观察者,在序列中有新的事件时调用该闭包,上面的代码会输出1,2,3。

Observer

观察者是实现了ObserverType协议的对象,ObserverType协议同样十分简单:

public protocol ObserverType {
    associatedtype E
    func on(_ event: Event<E>)
}

E为观察者所观察序列中的元素类型,当序列中有新的事件产生时,会调用on方法来接收新的事件。其中事件的类型Event是一个枚举,其中包含3个类型:

enum Event<Element> {
    case next(Element)
    case error(Swift.Error)
    case completed
}
  1. .next:表示序列中产生了下一个事件,关联值Element保存了该事件的值。
  2. .error:序列产生了一个错误,关联值Error保存了错误类型,在这之后序列会直接结束(不再产生新的next事件)。
  3. .completed:序列正常结束。

Dispose

除了产生错误和自然结束以外,还可以手动结束观察,在使用subscribe订阅一个可观察序列时,会返回一个Disposable类型的对象。这里的Disposable是一个协议,只定义了一个方法:

protocol Disposable {
    func dispose()
}

dispose方法用来结束此次订阅并释放可观察序列中的相关资源,通常来说你并不需要直接调用该方法,而是通过调用其扩展方法addDisposableToDisposable添加到一个DisposeBag对象中。DisposeBag对象会自动管理所有添加到其中的Disposable对象,在DisposeBag对象销毁的时候会自动调用其中所有Disposable的dispose方法释放资源。

也可以使用takeUntil来自动结束订阅:

seq.takeUntil(otherSeq)
    .subscribe({ (event) in
        print(event)
    })

在otherSeq序列发出任意类型的事件之后,自动结束本次订阅。

创建序列

通过Observable类型提供的方法create可以创建一个自定义的可观察序列:

let seq = Observable<Int>.create { (observer) -> Disposable in
    observer.on(.next(1))
    observer.on(.completed)
    return Disposables.create {
        // do some cleanup
    }
}

create方法使用一个闭包来创建自定义的序列,闭包接收一个ObserverType的参数observer,并通过observer来发送相应的事件。如上面的代码,创建了一个Observable<Int>类型的可观察序列,订阅该序列的观察者会收到事件1和一个完成事件。最后create方法返回一个自己创建的Disposable对象,可以在这里进行一些相关的资源回收操作。

除了create方法之外,RxSwift中提供了很多中简便的方法用于创建序列,常用的有:

Share

通常在我们在订阅一个可观察序列的时候,每一次的订阅行为都是独立的,也就是说:

let seq = Observable.of(1, 2)
// 1
seq.subscribe { (event) in
    print("sub 1: \(event)")
}
// 2
seq.subscribe { (event) in
    print("sub 2: \(event)")
}
---- example output ----
sub 1: next(1)
sub 1: next(2)
sub 1: completed 
sub 2: next(1)
sub 2: next(2)
sub 2: completed 

我们连续订阅同一序列两次,每次都会接收到相同的事件,第二次订阅时并没有因为第一次订阅的行为导致元素"耗尽"。有些时候我们希望让所有的观察者都共享同一份事件,这个时候可以使用share

序列的变换和组合

在Swift的序列Sequence中,可以使用map、flatMap和reduce等常见的函数式方法对其中的元素进行变换,RxSwift中的可观察序列同样也支持这些方法。

变换

组合

Subject

Subject对象相当于一种中间的代理和桥梁的作用,它既是观察者又是可观察序列,在向一个Subject对象添加观察者之后,可以通过该Subject向其发送事件。Subject对象并不会主动发送completed事件,并且在发送了error或completed事件之后,Subject中的序列会直接终结,无法再发送新的消息。Subject同样也分为几种类型:

Scheduler

Scheduler是RxSwift中进行多线程编程的一种方式,一个Observable在执行的时候会指定一个Scheduler,这个Scheduler决定了在哪个线程对序列进行操作以及事件回调。默认情况下,在订阅Observable之后,观察者会在与调用subscribe方法时相同的线程收到通知,并且也会在该线程进行销毁(dispose)。

与GCD类似,Scheduler分为串行(serial)和并行(concurrent)两种类型,RxSwift中定义了几种Schedular:

subscribeOn和observeOn

subscribeOnobserveOn是其中两个最重要的方法,它们可以改变Observable所在的Scheduler:

// main thread
let scheduler = ConcurrentDispatchQueueScheduler(qos: .default)
let seq = Observable.of(1, 2)
seq.subscribeOn(scheduler)
    .map {
        return $0 * 2 // 子线程
    }
    .subscribe { (event) in
        print(event) // 子线程
    }

在上面的代码中创建了一个并发的Scheduler,并在序列seq上调用subscribeOn指定了该Scheduler,可以看到,我们在主线程中订阅该序列,但是map方法以及事件的回调都是在创建的子线程中执行。

subscribeOnobserveOn都可以指定序列的Scheduler,它们之间的区别在于:

createObservable().
    .doSomething()
    .subscribeOn(scheduler1) // (1)
    .doSomethingElse()
    .observeOn(scheduler2) // (2)
    .doAnother()
    ...

如上代码,在(1)处执行了subscribeOn之后,之前的操作createObservable()和doSomething()都会在scheduler1中执行,随后的doSomethingElse()同样也在scheduler1中执行,随后用observeOn指定了另外一个scheduler2,之后的doAnother()会在scheduler2上执行。

为原有代码添加Rx扩展

RxSwift中提供了一种扩展机制,可以很方便的为原有的代码添加上Rx扩展。首先来看一个结构体Reactive

public struct Reactive<Base> {
    /// base是扩展的对象实例
    public let base: Base
    
    public init(_ base: Base) {
        self.base = base
    }
}

Reactive是一个泛型结构体,只定义了一个属性base,并且在初始化结构体的时候传入该属性的值。

此外还定义了一个协议ReactiveCompatible

public protocol ReactiveCompatible {
    associatedtype CompatibleType

    static var rx: Reactive<CompatibleType>.Type { get set }
    var rx: Reactive<CompatibleType> { get set }
}

该协议中分别为类对象和实例对象定义一个名字相同的属性:rx,类型为上面定义的Reactive,随后通过协议扩展为其提供了get的默认的实现:

extension ReactiveCompatible {
    public static var rx: Reactive<Self>.Type {
        get {
            return Reactive<Self>.self
        }
        set {
            // this enables using Reactive to "mutate" base type
        }
    }

    public var rx: Reactive<Self> {
        get {
            return Reactive(self)
        }
        set {
            // this enables using Reactive to "mutate" base object
        }
    }
}

关联类型CompatibleType被自动推导为实现该协议的类本身,使用self初始化一个Reactive对象。

最后通过协议扩展为所有的NSObject类型实现了ReactiveCompatible协议:

extension NSObject: ReactiveCompatible { }

这样一来,代码中所有继承自NSObject的类型实例中都会有一个类型为Reactive的属性rx,当我们要为自己的类型添加Rx扩展时,只需要通过扩展向Reactive中添加方法就可以了,例如向UIButton类型添加扩展:

extension Reactive where Base: UIButton { // 为Reactive<UIButton>添加扩展
    public var tap: ControlEvent<Void> {
        return controlEvent(.touchUpInside) // 通过base可以访问该实例本身
    }
}

由于Reactive是一个泛型类型,我们可以通过where语句指定泛型的类型,这样一来,我们就可以在UIButton实例的rx中访问tap属性了:

let button = UIButton(...)
button.rx.tap

类似RxCocoa这样的RxSwift扩展库都是通过这种方式进行Rx扩展的。

上一篇 下一篇

猜你喜欢

热点阅读