(十六)RxSwift之Subject

256 阅读3分钟

在我们所遇到的事物中,有一部分非常特别。它们既是可监听序列(Observable)也是观察者(Observer)。

相同点:一次发送,处处订阅,区别如下表

类型 描述
PublishSubject 订阅以后产生的所有元素
BehaviorSubject 订阅时会将最新的元素发出来
ReplaySubject 保存最新的n个元素
AsyncSubject 只订阅最后一个和完成事件 或 错误事件
  • PublishSubject

PublishSubject 将对观察者发送订阅后产生的元素,而在订阅前发出的元素将不会发送给观察者。

示例:

let publishSub = PublishSubject<Int>()
publishSub.onNext(1)
publishSub.subscribe {print("订阅1:\($0)")}
    .disposed(by: self.disposeBag)
publishSub.onNext(2)
publishSub.onNext(3)
publishSub.subscribe {print("订阅2:\($0)")}
    .disposed(by: self.disposeBag)
publishSub.onNext(4)
publishSub.onNext(5)

输出:

订阅1:next(2)
订阅1:next(3)
订阅1:next(4)
订阅2:next(4)
订阅1:next(5)
订阅2:next(5)
  • BehaviorSubject

当观察者对 BehaviorSubject 进行订阅时,它会将源 Observable 中最新的元素发送出来(如果不存在最新的元素,就发出默认元素)

示例:

let behaciorSub = BehaviorSubject(value: 1)
behaciorSub.onNext(2)
behaciorSub.onNext(3)
behaciorSub.subscribe {print("订阅1:\($0)")}
    .disposed(by: self.disposeBag)
behaciorSub.onNext(4)
behaciorSub.onNext(5)
behaciorSub.subscribe {print("订阅2:\($0)")}
    .disposed(by: self.disposeBag)
behaciorSub.onNext(6)

输出:

订阅1:next(3)
订阅1:next(4)
订阅1:next(5)
订阅2:next(5)
订阅1:next(6)
订阅2:next(6)
  • ReplaySubject

ReplaySubject 将最新的 n 个元素发送给观察者

示例:

let replaySub = ReplaySubject<Int>.create(bufferSize: 2)
replaySub.onNext(1)
replaySub.onNext(2)
replaySub.onNext(3)
replaySub.subscribe {print("订阅1:\($0)")}
    .disposed(by: self.disposeBag)
replaySub.onNext(4)
replaySub.onNext(5)
replaySub.subscribe {print("订阅2:\($0)")}
    .disposed(by: self.disposeBag)
replaySub.onNext(6)

输出:

订阅1:next(2)
订阅1:next(3)
订阅1:next(4)
订阅1:next(5)
订阅2:next(4)
订阅2:next(5)
订阅1:next(6)
订阅2:next(6)
  • AsyncSubject

AsyncSubject 将在源 Observable 产生完成事件后,发出最后一个元素(仅仅只有最后一个元素),如果源 Observable 没有发出任何元素,只有一个完成事件。那 AsyncSubject 也只有一个完成事件。如果发出错误事件,只有一个错误事件。

示例:

let asynSub = AsyncSubject<Int>.init()
    asynSub.onNext(1)
    asynSub.onNext(2)
    asynSub.onNext(3)
    asynSub.subscribe {print("订阅1:\($0)")}
        .disposed(by: self.disposeBag)
    asynSub.onNext(4)
    asynSub.onNext(5)
    asynSub.subscribe {print("订阅2:\($0)")}
        .disposed(by: self.disposeBag)
    asynSub.onNext(6)
//   asynSub.onError(NSError.init(domain: "error", code: 10086, userInfo: nil))
    asynSub.onCompleted()

输出:

输出:
订阅1:next(6)
订阅2:next(6)
订阅1:completed
订阅2:completed
or
订阅1:error(Error Domain=error Code=10086 "(null)")
订阅2:error(Error Domain=error Code=10086 "(null)")

分析一个PublishSubject,其他的就是在初始化时有一点区别。

let publishSub = PublishSubject<Int>()
publishSub.onNext(1)
publishSub.subscribe {print("订阅1:\($0)")}
    .disposed(by: self.disposeBag)
publishSub.onNext(2)

(一)、首先来看PublishSubject的初始化:

public final class PublishSubject<Element>
    : Observable<Element>
    , SubjectType
    , Cancelable
    , ObserverType
    , SynchronizedUnsubscribeType {
    public typealias SubjectObserverType = PublishSubject<Element>
    
    /// Creates a subject.
    public override init() {
        super.init()
        #if TRACE_RESOURCES
            _ = Resources.incrementTotal()
        #endif
    }
    
    public func on(_ event: Event<Element>) {
        #if DEBUG
            self._synchronizationTracker.register(synchronizationErrorMessage: .default)
            defer { self._synchronizationTracker.unregister() }
        #endif
        dispatch(self._synchronized_on(event), event)
    }

点进PublishSubject代码中我们可以看见在初始化函数init中什么也没做,但是它有一个on函数并且可以看到PublishSubject继承于SubjectType

public protocol SubjectType : 'ObservableType' {
/// The type of the observer that represents this subject.
///
/// Usually this type is type of subject itself, but it doesn‘t have to be.
associatedtype Observer: 'ObserverType'

@available(*, deprecated, message: Use `Observer` instead.)
typealias SubjectObserverType = Observer

/// Returns observer interface for subject.
///
/// - returns: Observer interface for subject.
func asObserver() -> Observer

我们可以看见SubjectType继承ObservableType,说明具有序列的特性,有subscribe函数,同时又关联ObserverType,具有观察者特性,具备on函数。可以看出,它即是可观察序列(Observable)又是观察者(Observer)。

(二)、发送信号

publishSub.onNext(1)

会来到PublishSubjecton函数

public func on(_ event: Event<Element>) {
    #if DEBUG
        self._synchronizationTracker.register(synchronizationErrorMessage: .default)
        defer { self._synchronizationTracker.unregister() }
    #endif
    dispatch(self._synchronized_on(event), event)
}

然后看见dispatch(self._synchronized_on(event), event),点进去

func _synchronized_on(_ event: Event<Element>) -> Observers {
    self._lock.lock(); defer { self._lock.unlock() }
    switch event {
    case .next:
        if self._isDisposed || self._stopped {
            return Observers()
        }
        
        return self._observers
    case .completed, .error:
        if self._stoppedEvent == nil {
            self._stoppedEvent = event
            self._stopped = true
            let observers = self._observers
            self._observers.removeAll()
            return observers
        }

        return Observers()
    }
}  

可以看到self._synchronized_on(event) 函数返回了 之前保存的观察者回调的收集,也就是下面函数的bag

func dispatch<Element>(_ bag: Bag<(Event<Element>) -> Void>, _ event: Event<Element>) {
    bag._value0?(event)

    if bag._onlyFastPath {
        return
    }

    let pairs = bag._pairs
    for i in 0 ..< pairs.count {
        pairs[i].value(event)
    }

    if let dictionary = bag._dictionary {
        for element in dictionary.values {
            element(event)
        }
    }
}

然后element(event)调用订阅时创建的观察者闭包,完成响应。

(三)进行订阅

publishSub.subscribe {print("订阅1:\($0)")}
    .disposed(by: self.disposeBag)

接下来,会来到subscribe函数,PublishSubjectsubscribe函数进行了重写。

public override func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element {
    self._lock.lock()
    let subscription = self._synchronized_subscribe(observer)
    self._lock.unlock()
    return subscription
}

为了保证顺序执行let subscription = self._synchronized_subscribe(observer)前后加了锁。

func _synchronized_subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element {
    if let stoppedEvent = self._stoppedEvent {
        observer.on(stoppedEvent)
        return Disposables.create()
    }
    
    if self._isDisposed {
        observer.on(.error(RxError.disposed(object: self)))
        return Disposables.create()
    }
    
    let key = self._observers.insert(observer.on)
    return SubscriptionDisposable(owner: self, key: key)
}

经过了一些排空判断后,来到let key = self._observers.insert(observer.on),这个方法是向当前的observers集合插入一个observer.on

mutating func insert(_ element: T) -> BagKey {
    let key = _nextKey

    _nextKey = BagKey(rawValue: _nextKey.rawValue &+ 1)

    if _key0 == nil {
        _key0 = key
        _value0 = element
        return key
    }

    _onlyFastPath = false

    if _dictionary != nil {
        _dictionary![key] = element
        return key
    }

    if _pairs.count < arrayDictionaryMaxSize {
        _pairs.append((key: key, value: element))
        return key
    }
    
    _dictionary = [key: element]
    
    return key
}

总结:

在订阅前发送.next响应,observer都还没有insert,所以会接收不到响应。所以PublishSubject的好处就是在需要用的时候才去订阅它,不用管之前的发送。