MRが楽しい

MRやVRについて学習したことを書き残す

UniRxでPublishを使ってColdの性質のObservableをHotの性質のObservableに変換する その2(PublishLastを使って最後の通知を保存する)

本日はUniRxの小ネタ枠です。
UniRxでPublishを使ってColdの性質のObservableをHotの性質のObservableに変換してみます。
今回はPublishLastオペレータを使って最後の通知を保存する動作を確認する

前回記事

Publishオペレータを使った場合のHotとColdのObservableの動作の違いは以下の前回記事を参照ください。
bluebirdofoz.hatenablog.com

PublishLastオペレータ

PublishLastオペレータはPublishオペレータと同様にColdのObservableをHotのObservableに変換することができます。
Publishとの違いはSubjectではなくAsyncSubjectを経由させるため、最後に発生した通知を受け取ることができます。

// ColdのObservable
var rangeObservable = Observable.Range(1, 2);

// PublishでHotのObservableの性質を持つObservableに変換されるが
// この時点でColdのObservableから通知は流れてこない
var rangeHotObservable = rangeObservable.PublishLast();

// Connectを行った時点でColdのObservableから通知が発生する
rangeHotObservable.Connect();

// ここで購読を行っても先ほど発生した通知の最後の値を受け取れる
rangeHotObservable.Subscribe(x => Debug.Log($"Subscribe1: {x}"));

サンプルスクリプト

以下のサンプルスクリプトでColdのObservableをPublishオペレータで変換したものを購読する場合と、PublishLastオペレータで変換したものを購読する場合の動作を比較します。
・PublishTest2.cs

using UniRx;
using UnityEngine;

public class PublishTest2 : MonoBehaviour
{
    [ContextMenu("PublishObservableTest")]
    public void PublishObservableTest()
    {
        // RangeオペレータはColdのObservableになる
        // Coldのため、この時点では 1, 2, 3 の通知が発行されない
        var rangeObservable = Observable.Range(1, 2);
        
        // PublishでHotのObservableを準備する
        // この時点ではColdのObservableから通知は流れてこない
        var rangeHotObservable = rangeObservable.Publish();

        // Connectを行った時点でColdのObservableから通知が発生する
        rangeHotObservable.Connect();
        
        Debug.Log("Subscribe");
        // 既に通知が完了しているため、ここの購読では通知が発生しない
        rangeHotObservable.Subscribe(x => Debug.Log($"Subscribe1: {x}"));
    }
    
    [ContextMenu("PublishLastObservableTest")]
    public void PublishLastObservableTest()
    {
        // RangeオペレータはColdのObservableになる
        // Coldのため、この時点では 1, 2, 3 の通知が発行されない
        var rangeObservable = Observable.Range(1, 2);
        
        // PublishでHotのObservableを準備する
        // この時点ではColdのObservableから通知は流れてこない
        var rangeHotObservable = rangeObservable.PublishLast();

        // Connectを行った時点でColdのObservableから通知が発生する
        rangeHotObservable.Connect();
        
        Debug.Log("Subscribe");
        // 既に通知は完了しているが、最後の 2 の通知を購読と同時に受け取る
        rangeHotObservable.Subscribe(x => Debug.Log($"Subscribe1: {x}"));
    }
}

Publishオペレータで変換したものを購読する場合

Publishオペレータで変換したObservableは過去に発生した通知を保持しません。
このため、Connect() を行った後に購読すると通知を受け取れません。

PublishLastオペレータで変換したものを購読する場合

PublishLishオペレータで変換したObservableは過去に発生した通知のうち、最後のものを保持して購読時に通知します。
このため、Connect() を行った後に購読しても最後に発生した通知だけは受け取ることができています。