UniRx: SubscribeWithState は Subscribe より効率がよい
以下のサンプルは、1 秒ごとにテキストを更新するサンプルです。
using System; using UniRx; using UnityEngine; using UnityEngine.UI; public class Main : MonoBehaviour { [SerializeField] private Text _text = null; void Start() { Observable.Interval(TimeSpan.FromSeconds(1f)) .Select(e => "Count " + e) .Subscribe(e => _text.text = e) .AddTo(this); } }
Subscribe
のところに注目してください。
.Subscribe(e => _text.text = e);
引数にクロージャを渡しています。このクロージャの生成コストを抑える手段があり、それはSubscribe
の代わりに SubscribeWithState
を使うことです。
void Start() { Observable.Interval(TimeSpan.FromSeconds(1f)) .Select(e => "Count " + e) // 外部変数を参照しないようになった(クロージャを排除できた) .SubscribeWithState(_text, (e, text) => text.text = e) .AddTo(this); }
UniRx ではこのパターンは SubscribeToText
というメソッドで定義されています。
public static partial class UnityUIComponentExtensions { public static IDisposable SubscribeToText(this IObservable<string> source, Text text) { return source.SubscribeWithState(text, (x, t) => t.text = x); } }
ですので、下のように書くことができます。
void Start() { Observable.Interval(TimeSpan.FromSeconds(1f)) .Select(e => "Count " + e) .SubscribeToText(_text) .AddTo(this); }
参考
- neue cc - Unityにおけるコルーチンの省メモリと高速化について、或いはUniRx 5.3.0でのその反映
SubscribeWithState
を使う上での UniRx 作者さんの解説があります。
- neue cc - Unityでのボクシングの殺し方、或いはラムダ式における見えないnewの見極め方
- クロージャおよび純粋な関数について、内部ではどのようなコードが生成されているかの解説があります。