【Unity】【UniRx】DoOnTerminateオペレータとFinallyオペレータの違い

UniRxのDoOnTerminateとFinallyの違いについてまとめました。

Unity2018.4.0
UniRx 6.2.2

DoOnCompleteとDoOnErrorの復習

UniRxにはストリームが完了した時に呼ばれるDoOnComplete()オペレータや
ストリームで例外が発生した時に呼ばれるDoOnError()オペレータがあります。

using UniRx;
using UnityEngine;

public class Example : MonoBehaviour
{
    private void Start()
    {
        Observable.Empty<Unit>()
            .DoOnCompleted(() => {}) // ストリームが完了した時に呼ばれる
            .DoOnError(ex => {}) // ストリーム内で例外が発生した時に呼ばれる
            .Subscribe()
            .AddTo(this);
    }
}

そしてストリームが終了するときにはOnCompleted()OnError()のどちらかが呼ばれるので、
上記のように処理を書いておけばストリーム終了時に何かしらの処理が行えます。

DoOnTerminateとFinallyの違いは?

ここで、DoOnTerminate()Finally()オペレータを記述すると、
その処理はOnCompleted()OnError()のどちらか一方が発生したら呼ばれます。

using UniRx;
using UnityEngine;

public class Example : MonoBehaviour
{
    private void Start()
    {
        Observable.Empty<Unit>()
            .DoOnTerminate(() => {}) // OnCompletedかOnError発生時に呼ばれる
            .Finally(() => {}) // OnCompletedかOnError発生時に呼ばれる
            .Subscribe()
            .AddTo(this);
    }
}

じゃあDoOnTerminate()Finally()ってどう違うんだろうという?という疑問が生まれます。

ストリームが破棄されるときに呼ばれるDoOnCancel

ここでDoOnCancel()というオペレータを紹介します。
これはストリームが破棄(Dispose)されたときに呼ばれる処理を記述できるオペレータです。

using UniRx;
using UnityEngine;

public class Example : MonoBehaviour
{
    private void Start()
    {
        var disposable = Observable.TimerFrame(300)
            .DoOnCancel(() => {}) // Disposeされたときに呼ばれる
            .Subscribe()
            .AddTo(this);

        disposable.Dispose();
    }
}

Finallyはストリームが破棄されたときも呼ばれる

次に、前節のコードにDoOnTerminate()Finally()オペレータを追加してみます。

using UniRx;
using UnityEngine;

public class Example : MonoBehaviour
{
    private void Start()
    {
        var disposable = Observable.TimerFrame(300)
            .DoOnTerminate(() => Debug.Log("DoOnTerminate"))
            .Finally(() => Debug.Log("Finally"))
            .Subscribe()
            .AddTo(this);

        disposable.Dispose();
    }
}

これを実行すると、Finallyだけがログ出力されることが確認できます。

f:id:halya_11:20190907130319p:plain

つまり、Finally()はストリームが破棄されたときにも呼ばれます。

まとめ

最後にDoOnTerminateとFinallyの違いを表にまとめておきます。

オペレータ 説明
DoOnTerminate 下記のいずれかのときに呼ばれる
・ストリームが完了(Complete)したとき
・ストリームで例外が発生(Error)したとき
Finally 下記のいずれかのときに呼ばれる
・ストリームが完了(Complete)したとき
・ストリームで例外が発生(Error)したとき
・ストリームが破棄(Dispose)されたとき

関連

light11.hatenadiary.com