【Unity】【UniRx】Repeat系のオペレータまとめ

UniRxのRepeat系のオペレータについてまとめました。

Repeat?

Repeatは、そのストリームがCompletedした際に、また新しく同じストリームを生成してSubscribe()します。

// 1秒おきにOn Next. と On Completed. が表示され続ける
Observable.Timer(System.TimeSpan.FromSeconds(1))
    .Do(_ => Debug.Log("On Next."))
    .DoOnCompleted(() => Debug.Log("On Completed."))
    .Repeat()
    .Subscribe()
    .AddTo(this);

無限ループの危険?

たとえば次のようなコードは無限ループになります。
Repeatを使うときには無限ループには気をつけないといけません。

// 無限ループ
Observable.Range(0, 3)
  .Do(x => Debug.Log("On Next. " + x))
  .DoOnCompleted(() => Debug.Log("On Completed."))
  .Repeat()
  .Subscribe()
  .AddTo(this);

また、下記のようなケースも無限ループとなります。
これは、CompleteしているSubjectをRepeatによりひたすら購読し続けるためです。

// 無限ループ
Subject<int> subject     = new Subject<int>();
subject
    .Do(x => Debug.Log("On Next. " + x))
    .DoOnCompleted(() => Debug.Log("On Completed."))
    .Repeat()
    .Subscribe();
subject.OnCompleted();

RepeatSafe

RepeatSafeオペレータはOnCompletedが連続できたときにRepeatを止めます。
前節の二つの例のうちの後者は、これにより防げます。

// 無限ループしない
Subject<int> subject     = new Subject<int>();
subject
    .Do(x => Debug.Log("On Next. " + x))
    .DoOnCompleted(() => Debug.Log("On Completed."))
    .RepeatSafe()
    .Subscribe();
subject.OnCompleted();

ただ全ての無限ループが防げるわけではないので注意が必要です。

RepeatUntilDisable

RepeatUntilDisableはGameObjectが非アクティブになるまで繰り返します。

// GameObjectが非アクティブになるまで繰り返す
Observable.Timer(System.TimeSpan.FromSeconds(1))
    .Do(_ => Debug.Log("On Next."))
    .DoOnCompleted(() => Debug.Log("On Completed."))
    .RepeatUntilDisable(gameObject)
    .Subscribe()
    .AddTo(this);

RepeatUntilDestroy

RepeatUntilDisableはGameObjectが破棄されるまで繰り返します。

// GameObjectが破棄されるまで繰り返す
Observable.Timer(System.TimeSpan.FromSeconds(1))
    .Do(_ => Debug.Log("On Next."))
    .DoOnCompleted(() => Debug.Log("On Completed."))
    .RepeatUntilDestroy(gameObject)
    .Subscribe()
    .AddTo(this);