RXSwift中 Subject的使用和分析

SubjectRxSwift 中一种特殊的序列, 最重要的特征是 它即为可观察序列, 也为观察者. 在实际开发中也最为常用,因此建议多了解其逻辑原理,对实际开发使用时有很大帮助。

为什么它是双重身份呢?
废话不多说,上代码

/// Represents an object that is both an observable sequence as well as an observer.
///
/// Each notification is broadcasted to all subscribed observers.
public final class PublishSubject
    : Observable
    , SubjectType
    , Cancelable
    , ObserverType
    , SynchronizedUnsubscribeType 

它继承于 ObservableObserverType , 因此 他既有 subscribe 功能,也有 on(_ event: Event) 功能

PublishSubject

  • 使用案例
// 1:初始化序列
let publishSub = PublishSubject() //初始化一个PublishSubject 装着Int类型的序列
// 2:发送响应序列
publishSub.onNext(1)
// 3:订阅序列
publishSub.subscribe { print("订阅到了:",$0)}
    .disposed(by: disposbag)
// 再次发送响应
publishSub.onNext(2)
publishSub.onNext(3)
  • 打印结果 :

订阅到了: next(2)
订阅到了: next(3)

  • 分析:
    cmd + 点击 PublishSubject 进入该类, 找到 on 方法,中间继承链查找方法流程不在多赘述
public func on(_ event: Event) {
    #if DEBUG
        self._synchronizationTracker.register(synchronizationErrorMessage: .default)
        defer { self._synchronizationTracker.unregister() }
    #endif
    dispatch(self._synchronized_on(event), event)
}

先来看 self._synchronized_on(event)

func _synchronized_on(_ event: Event) -> 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()
    }
}

返回的是当前 PublishSubjectObservers ,一个 Bag对象,可以理解为数组, 也就是当前观察者数组.

再点击 dispatch 找到如下方法:

func dispatch(_ bag: Bag<(Event) -> Void>, _ event: Event) {
    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)
        }
    }
}

可以看到,该方法是循环自己保存的所有观察者,调用发送 event ,在第一次执行 publishSub.onNext(1) 时, 并没有观察者, 因此并无响应.

则回到代码中 下一步

publishSub.subscribe { print("订阅到了:",$0)}

进入 PublishSubject 类寻找 subscribe 方法
过度方法:

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

再进入 _synchronized_subscribe

func _synchronized_subscribe(_ observer: O) -> Disposable where O.E == E {
    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)
}

可以明显看到 订阅一次,就在观察者数组中插入这个观察者.

因此, PublishSubject 在未订阅时,所发送的 event是没有响应的, 后续发送 会查找所有观察者, 循环遍历, 一一发送响应.

BehaviorSubject

  • 使用案例
let behaviorSub = BehaviorSubject.init(value: 100)
// 2:发送信号
behaviorSub.onNext(2)
behaviorSub.onNext(3)
// 3:订阅序列
behaviorSub.subscribe{ print("订阅到了:",$0)}
    .disposed(by: disposbag)
// 再次发送
behaviorSub.onNext(4)
behaviorSub.onNext(5)
// 再次订阅
behaviorSub.subscribe{ print("订阅到了:",$0)}
    .disposed(by: disposbag)
  • 打印结果 :

订阅到了: next(3)
订阅到了: next(4)
订阅到了: next(5)
订阅到了: next(5)

注释掉 behaviorSub.onNext(2)behaviorSub.onNext(3)
打印结果:

订阅到了: next(100)
订阅到了: next(4)
订阅到了: next(5)
订阅到了: next(5)

  • 分析 :
public init(value: Element) {
    self._element = value

    #if TRACE_RESOURCES
        _ = Resources.incrementTotal()
    #endif
}

初始化时,保存了传进来的默认值到自己的 _element 属性中.
后续每次发送 behaviorSub.onNext(2),来到如下方法

public func on(_ event: Event) {
    dispatch(self._synchronized_on(event), event)
}

func _synchronized_on(_ event: Event) -> Observers {

    switch event {
    case .next(let element):
        self._element = element
    case .error, .completed:
        self._stoppedEvent = event
    }
    
    return self._observers
}

可以看到,跟 PublishSubject 基本差不多,除了给所有观察者发送事件以外,多了一步

self._element = element

也就是保存了最新发送的 element

同样,subscribe 方法:

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

func _synchronized_subscribe(_ observer: O) -> Disposable where O.E == E {
    
    let key = self._observers.insert(observer.on)
    observer.on(.next(self._element))

    return SubscriptionDisposable(owner: self, key: key)
}

subscribe 方法也是跟 PublishSubject 基本一致,除了把此次观察者添加保存,多了一步

observer.on(.next(self._element))

也就是说在订阅时 会默认发送一次 on next 事件,发送内容为保存的最新 element

ReplaySubject

  • 使用案例
    // 1:创建序列
    let replaySub = ReplaySubject.create(bufferSize: 2)
    // let replaySub = ReplaySubject.createUnbounded()
    
    // 2:发送信号
    replaySub.onNext(1)
    replaySub.onNext(2)
    replaySub.onNext(3)
    replaySub.onNext(4)
    
    // 3:订阅序列
    let disposbag = DisposeBag()
    replaySub.subscribe{ print("订阅到了:",$0)}
        .disposed(by: disposbag)
    // 再次发送
    replaySub.onNext(7)
    replaySub.onNext(8)
    replaySub.onNext(9)

  • 打印结果 :

订阅到了: next(3)
订阅到了: next(4)
订阅到了: next(7)
订阅到了: next(8)
订阅到了: next(9)

  • 分析
    ReplaySubjectBehaviorSubject 其实实现原理基本类似,只不过后者是用一个 _element 属性来记录最新一次的 event 值,而前者在给定的 bufferSize 大于1时使用 _queue 来存储一组 Element,等于1时 使用一个 _value 属性来记录最新一次的 event 值。

AsyncSubject

  • 使用案例
    // AsyncSubject
    // 1:创建序列
    let asynSub = AsyncSubject.init()
    // 2:发送信号
    asynSub.onNext(1)
    asynSub.onNext(2)
    // 3:订阅序列
    let disposbag = DisposeBag()
    asynSub.subscribe{ print("订阅到了:",$0)}
        .disposed(by: disposbag)
    // 再次发送
    asynSub.onNext(3)
    asynSub.onNext(4)
//        asynSub.onError(NSError.init(domain: "lb", code: 10086, userInfo: nil))
    asynSub.onCompleted()
  • 打印结果

订阅到了: next(4)
订阅到了: completed

打开注释掉的 onError这一行

  • 打印结果

订阅到了: error(Error Domain=lb Code=10086 "(null)")

  • 分析
    直接查看源码
public func on(_ event: Event) {
    #if DEBUG
        self._synchronizationTracker.register(synchronizationErrorMessage: .default)
        defer { self._synchronizationTracker.unregister() }
    #endif
    let (observers, event) = self._synchronized_on(event)
    switch event {
    case .next:
        dispatch(observers, event)
        dispatch(observers, .completed)
    case .completed:
        dispatch(observers, event)
    case .error:
        dispatch(observers, event)
    }
}

继续点击 _synchronized_on 方法

func _synchronized_on(_ event: Event) -> (Observers, Event) {
    
    switch event {
    case .next(let element):
        self._lastElement = element
        return (Observers(), .completed)
    case .error:
        self._stoppedEvent = event

        let observers = self._observers
        self._observers.removeAll()

        return (observers, event)
    case .completed:

        let observers = self._observers
        self._observers.removeAll()

        if let lastElement = self._lastElement {
            self._stoppedEvent = .next(lastElement)
            return (observers, .next(lastElement))
        }
        else {
            self._stoppedEvent = event
            return (observers, .completed)
        }
    }
}

上面可以看到其实 AsyncSubject 在接收到 on(_ event: Event) 事件时 只有在接收到 .completed 事件时,才会自动发送一次 .next(lastElement)AsyncSubject 在实际开发中使用的并不多。

AsyncSubject 在完成时发出最后一个元素,如果源 Observable 没有发出任何元素,只有一个完成事件,则 AsyncSubject 也只有一个完成事件。如果源 Observable 产生了一个 error 事件而中止,那么 AsyncSubject 就不会发出任何元素,而是将 error 事件发送出来。

Variable

Variable 在5.0版本中已经废弃,使用( BehaviorSubject 或者 BehaviorRelay 替换)

  • 使用案例
    let variableSub = Variable.init(1)
    // 2:发送信号
    variableSub.value = 100
    variableSub.value = 10
    // 3:订阅信号
    let disposbag = DisposeBag()
    variableSub.asObservable().subscribe{ print("订阅到了:",$0)}
        .disposed(by: disposbag)
    // 再次发送
    variableSub.value = 1000
  • 打印结果:

订阅到了: next(10)
订阅到了: next(1000)

  • 分析

从源码可以看出,Variable 虽然没有继承自 ObserverType 或者 Observable 。但是其有一个 _subject: BehaviorSubject 属性。所以,Variable 的行为和 BehaviorSubject 是一致的。但因为不是继承自 ObserverType,所以没有 on 函数,不能直接调用 on 函数发送信号。

在初始化时,使用初始化值,初始化 BehaviorSubject,并保存在 self._subject 中。
value 做了一层封装,在 valueset 函数中,会调用 _subjecton 函数。完成信号的发送。

public typealias E = Element

    private let _subject: BehaviorSubject

    // state
    private var _value: E

    public var value: E {
        get {
            self._lock.lock(); defer { self._lock.unlock() }
            return self._value
        }
        set(newValue) {
            #if DEBUG
                self._synchronizationTracker.register(synchronizationErrorMessage: .variable)
                defer { self._synchronizationTracker.unregister() }
            #endif
            self._lock.lock()
            self._value = newValue
            self._lock.unlock()

            self._subject.on(.next(newValue))
        }
    }

BehaviorRelay

BehaviorRelay 就是 BehaviorSubject 去掉终止事件 onErroronCompleted

  • 使用案例:
let subject = BehaviorRelay(value: 1)
subject.accept(10)

subject.subscribe({ print("订阅到:\($0)")})
    .disposed(by: disposeBag)

subject.accept(100)
subject.accept(1000)
  • 打印结果:

订阅到:next(10)
订阅到:next(100)
订阅到:next(1000)

  • 分析

    查看源码,请注意 BehaviorRelay 上方的注释,注释中说得非常清楚,BehaviorRelay 是对 BehaviorSubject 的封装,但是和 BehaviorSubject 不一样的地方在于,BehaviorRelay 不会被 errorcompleted 事件终止。

BehaviorRelayVariable 类似, 无需手写 on(event)事件,只需给属性赋值即可拿到响应事件内容,是我们开发中最常用的序列。

你可能感兴趣的:(RXSwift中 Subject的使用和分析)