LoginSignup
5

More than 5 years have passed since last update.

UniRxのReactiveProperty他の配列を扱う場合の注意点

Last updated at Posted at 2017-12-25

UniRxで配列を扱った時個人的に詰まったとこの解決
また、別にReactivePropertyに限った話ではないので注意。

その1

UniRxでReactivePropertyを使うことはよくあると思う。
で、それを使って配列を扱いたいともちろん思うと思う。

RxManager
public class RxManager : MonoBehaviour {

  public StringReactiveProperty[] data;

}

例えばこれを扱うとする。で、購読側がこんな感じ
やりたいことはdataが変更したらView classにその変更をする通知をする

Passenger
public class Passenger : MonoBehaviour {

       public RxManager manager;
       public View view;
   void Start(){
        //これは失敗する!
        for (int i = 0; i < manager.data.Length; i++) {
            manager.data[i].Subscribe (x => view.showButton (i,x));
        }

}

で、これは失敗する。
view.showButton (i,x)のiが
なぜか常にi = Lengthの値になるのだ

で、早速解決方法

Passenger
public class Passenger : MonoBehaviour {

       public RxManager manager;
       public View view;
   void Start(){
        for (int i = 0; i < manager.data.Length; i++) {
            ////reactivepropatyで配列を扱う場合、一度変数を受ける           
            int a = i;
            manager.data[a].Subscribe (x => view.showButton (a,x));
        }

}

いいたいことはわかる。aもiも同じじゃないのかと。なぜ一回受けるのかと
でもまあちょっと古いC#クエリ式(Subscribe (x =>)でやる場合、こうなのだと思ってほしい。
また、補足であるがViewはこんな感じ

View
public class View : MonoBehaviour {
        public Button[] itembtn;
        public Text[] itemtext;

        public void showButton(int num,string text){
            itemtext [num].text = text;
        }
    }

これでRxManagerの値を何らかの方法で変化させるだけでそれに応じたボタンのテキストも変更されるというわけ。
ItemMenu画面とかに使えると思う。

その2 CopyTo()

を使うとストリームごとコピーしてしまう。

ReactiveCopy
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniRx;
using UnityEngine.UI;
public class ReactiveCopy: MonoBehaviour {
    public IntReactiveProperty[] tesint = new IntReactiveProperty[5];
    public IntReactiveProperty[] tesint2 = new IntReactiveProperty[5];


    void Start(){
        for(int i = 0;i < tesint.Length;i++){
            int a = i;
            tesint [i].Subscribe (x => tesint2[a].Value = x).AddTo (gameObject);
            tesint2 [i].Subscribe (x => Debug.Log ("s" + x));
        }
    }
    //copytoでストリームごとコピーされる。
    public void copyint(){
        tesint.CopyTo (tesint2, 0);

    }

}

これでcopyint関数を後から実行するとtestint[]のストリームがtestint2[]のストリームに上書きされる。
のでこのプログラムだとtestint[]の値を変更するとdebug.logが表示される。
解決法としては一回変数を受けてからなのだろうか、現在検証中。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5