質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

5214閲覧

UniRxのAddToについて質問です。

daikon326

総合スコア11

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2019/05/13 05:31

最近UniRxを使い始めたもので、UniRxのAddToについて質問です。
AddToを使うと自分で手動でDisposeしなくても引数で指定したObjectが破棄されたときに、自動的にサブスクリプションがDisposeされるのは分かったのですが、

例えばボタンに対して

該当のソースコード

C#

1public class Test : MonoBehaviour 2{ 3 [SerializeField] 4 Button button; 5 6 void Start() 7 { 8 button.OnClickAsObservable().Subscribe(_ => { 9 Debug.Log("Click!"); 10 }); 11 } 12 13}

のようにした場合で、Testクラスとbuttonがほぼ同じライフサイクル(シーン遷移などでほぼ同時に作られて、ほぼ同時に削除される場合など)
のときでもAddToしないと問題になりますでしょうか?
イベントが飛んでくることはないのですが、メモリリークなどが起きてしまうのかが気になったもので。

また、どうのようなときにAddToを使うべきかなどアドバイスあれば幸いです。

よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

ご提示のコードを拝見する限りでは、buttonTestのどちらが先に削除されても現状のコードにおいてはさほど問題はなさそうに思います。ですが今後どんどんコードを追加していって依存関係が複雑になると、場合によってはAddToを行わないと問題が起きるかもしれません。

まず、OnClickAsObservableによって作られたストリームの寿命はbuttonの寿命に依存していると考えられます。buttonが先に破壊されたとすると、そのタイミングで自動的にストリームが完了するのでTestが行ったサブスクリプションもそこで解除されるでしょう。
逆にTestが先に破壊されたらどうなるかですが、今のところTestの役割はStartのタイミングでSubscribeを行うだけであり、Startが終わったらTestはいてもいなくても動作に影響はないはずです。ですので、仮に下記のようにすると...

C#

1using UniRx; 2using UnityEngine; 3using UnityEngine.UI; 4 5public class Test : MonoBehaviour 6{ 7 [SerializeField] Button button; 8 9 void Start() 10 { 11 this.button.OnClickAsObservable().Subscribe(_ => { Debug.Log("Click!"); }); 12 } 13 14 void Update() 15 { 16 if (Time.time > 3.0f) 17 { 18 // 3秒後に自身を破壊 19 Debug.Log($"Destroy {this.name}"); 20 Destroy(this.gameObject); 21 } 22 } 23}

下図のようにTest破壊後もサブスクリプションが解除されずに動作し続けるでしょう。

結果1

クリック時の動作が今回のような固定された文章を表示するだけであれば、サブスクリプションはTestが生きているかどうかに依存しませんので問題ないでしょう。
しかし、もし下記のようにTestが生きていないとまずいような動作をさせている場合は...

C#

1using UniRx; 2using UnityEngine; 3using UnityEngine.UI; 4 5public class Test : MonoBehaviour 6{ 7 [SerializeField] Button button; 8 9 void Start() 10 { 11 // クリックされたら自身の座標を出力する 12 // 正常に実行するには、クリックされた時点でこのオブジェクトが生きていなければならない 13 this.button.OnClickAsObservable().Subscribe(_ => { Debug.Log(this.transform.position); }); 14 } 15 16 void Update() 17 { 18 if (Time.time > 3.0f) 19 { 20 // 3秒後に自身を破壊 21 Debug.Log($"Destroy {this.name}"); 22 Destroy(this.gameObject); 23 } 24 } 25}

下図のようにトラブルが発生する可能性があります。

結果2

このような場合にAddToを行っておけば...

C#

1using UniRx; 2using UnityEngine; 3using UnityEngine.UI; 4 5public class Test : MonoBehaviour 6{ 7 [SerializeField] Button button; 8 9 void Start() 10 { 11 // 自身の破壊に連動してサブスクリプションを解除するよう設定 12 this.button.OnClickAsObservable().Subscribe(_ => { Debug.Log(this.transform.position); }).AddTo(this); 13 } 14 15 void Update() 16 { 17 if (Time.time > 3.0f) 18 { 19 // 3秒後に自身を破壊 20 Debug.Log($"Destroy {this.name}"); 21 Destroy(this.gameObject); 22 } 23 } 24}

Test破壊後はボタンを押しても何も起こらないようになるでしょう。

結果3

ご質問者さんの場合はTestbuttonの破壊がほぼ同タイミングとのことですから、Testが破壊されてbuttonがまだ生きている一瞬の間にクリックイベントが来ないかぎりはトラブルを起こさないだろうと予想されますが、念のため警戒しておいた方がいいかと思います。

AddToを行うべきかどうかは依存関係を考慮して決めるのがいいだろうとは思いますが、とりあえずAddToを行っておくという方針でもあまり害はなさそうな気もします。オブジェクトに自動的にDispose処理担当のコンポーネントが追加されたりするようですので多少は処理コストがかかるのかもしれませんが、気軽にAddToを使えなくなるほどのマイナス点ではなさそうに見えます。

AddToの使いどころとして、説明文書の中ではObservable Lifecycle Managementの節にAddToが登場しています。
Observable.TimerObservable.EveryUpdateのような静的ジェネレーターで作ったストリームは手動で切らないと動きっぱなしになるとのことですので、それらをスマートに処分するのには便利そうですね。

投稿2019/05/14 11:50

Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

daikon326

2019/05/15 12:07

回答ありがとうございます。詳細に検証までしていただき、非常に助かります。 おっしゃる通り依存関係をちゃんと考えて設計して、エラーが出そうな怪しいところはAddToをつけておこうかと思います。 説明文書にちゃんと書かれていたのですね。ちゃんと読まないといけませんね。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問