🍎

[RxSwift]SubjectとRelayの違い

2022/03/03に公開

経緯

どちらもObservableのイベント検知から、
イベントを流すことまで可能なクラスですが、
時間経過と共にどちらを使用すべきか調べ直している気がしていて、
改めてしっかりと違いを整理しておきたかったため。

Subject

Subjectは以下の3種類のイベントを流すことができます。
onNext, onError, onComplete
こちらの3種類のイベントについては、
後ほど詳しく記載します。

それからSubjectには以下の2種類があり、

  1. PublishSubject
  2. BehaviorSubject

このPublishBehaviorは後述するRelayにも存在します。
違いに関しては後ほど記載します。

Relay

RelayにはSubjectではあった種類のイベントは無く、
onNextのみ流すことが可能です。
onErroronCompleteは流れてこないことが保証されています。
それからRelayにもPublishBehaviorの2種類があります。

上記onNextに値を流す方法は、acceptを使用します。

accept使用例
let publishRelay = PublishRelay<Int>()
 
publishRelay.subscribe { num in
    print(num)
}.disposed(by: disposeBag)
 
publishRelay.accept(99)

3種類のイベントについて

以下の公式のソースコードを見てみると理解が深まるかと思います。
https://github.com/ReactiveX/RxSwift/blob/main/RxSwift/ObserverType.swift
実際のソースはこちら。

ObserverType.swift
//
//  ObserverType.swift
//  RxSwift
//
//  Created by Krunoslav Zaher on 2/8/15.
//  Copyright © 2015 Krunoslav Zaher. All rights reserved.
//
/// Supports push-style iteration over an observable sequence.
public protocol ObserverType {
    /// The type of elements in sequence that observer can observe.
    associatedtype Element

    /// Notify observer about sequence event.
    ///
    /// - parameter event: Event that occurred.
    func on(_ event: Event<Element>)
}

/// Convenience API extensions to provide alternate next, error, completed events
extension ObserverType {
    
    /// Convenience method equivalent to `on(.next(element: Element))`
    ///
    /// - parameter element: Next element to send to observer(s)
    public func onNext(_ element: Element) {
        self.on(.next(element))
    }
    
    /// Convenience method equivalent to `on(.completed)`
    public func onCompleted() {
        self.on(.completed)
    }
    
    /// Convenience method equivalent to `on(.error(Swift.Error))`
    /// - parameter error: Swift.Error to send to observer(s)
    public func onError(_ error: Swift.Error) {
        self.on(.error(error))
    }
}

onNextは引数でElementを送り、
onErrorSwift.Errorを送ります。
onCompleteは何も送ることはなくそのイベントのみです。

PublishとBehaviorの違い

Behaviorは、subscribe時に1つ直前のイベントを受け取ることが可能で、
最初にsubcribeするときは、設定した初期値を受け取ることになります。
反対にPublishの場合は初期値を持たず、過去のイベントは流れません。
この過去の値や初期値のことをバッファが有無でよく記載されます。

Behavior使用例
// バッファ有
let behaviorSubject = BehaviorSubject<Int>(value: 1)
// バッファ無
let publishRelay = PublishSubject<Int>()

まとめ

このように大きく分けSubjectとRelayの違いを説明しましたが、
その中にPublishとBehaviorでも違いがあるので、
適切なものを定義していきたいです。

Discussion