UniRX 배우기 2) Observable 객체 생성하기

 

 

스트림을 만들기 위해서는 관찰 가능한 객체(Observable)를 생성해야 한다.

기존의 델리게이트를 사용하는 객체를 변환할 수도 있고, 별도의 객체를 만들어서 수동으로 메시지를 발행할 수도 있다.

 

 

1. Subject 형식을 통해 직접 Observable 객체 만들기

앞서 살펴본 바와 같이 ISubject<T>는 IObservable<T>를 구현하고 있다.

subject 객체는 IObserver<T>또한 구현하고 있기 때문에, 직접 메시지를 발행할 수 있다.

Subject<int> mySubject = new Subject<int>();
mySubject.AsObservable().Subscribe(n => SomeMethod(n));

// subject객체를 통해 직접 메시지 발행 가능
mySubject.OnNext(0);
mySubject.OnCompleted();

 

1-1) PublishSubject

 - 구독 이후에 Observable이 배출한 메시지만 배출한다.

 

1-2) AsyncSubject

 - Observable가 종료될 때, 구독중인 Observer들에게 마지막 값을 배출한다. 

 - 중간에 오류가 발생하였다면 어떠한 값도 배출되지않고 오류 메시지만을 보낸다.

 

1-3) BehaviorSubject

 - 구독을 시작할 때 가장 최근에 발행한 메시지를 초기값으로 배출한다.

 

1-4) ReplaySubject

 - 구독 시작 시점과 관계없이 지금까지 Observable이 배출한 항목들을 observer에게 배출한다.

 - 중간에 오류가 발생하였다면 일련의 메시지들을 순서대로 전달 후, 마지막에 오류 메시지를 배출한다.

 

 

2. UnityEvent를 Observable로 변환하기

2-1) 버튼 클릭 감지하기

 - UGUI의 Button.onClick은 UnityEvent라서 UniRX가 제공하는 .Subscribe()를 통해 콜백을 받을 수 있다.

 - 아래의 AsObservable()의 반환형은 IObservable<T>이다. (LINQ의 IEnumerable<T>에 해당)

[SerializeField] Button button;
[SerializeField] Text text;

void Start()
{
    // 첫번째 예시
    button.onClick
        .AsObservable() // 이벤트를 스트림으로 변경
        .Subscribe(_ => 
        { 
            text.text = "눌렀다" 
        });
}

 UniRX는 UGUI를 위해 단축형 확장 메서드를 지원한다. 아래의 코드는 위의 코드와 같은 동작을 한다.

button.OnClickAsObservable().SubscribeToText(text, _ => "눌렀다");

 

 

3. Update를 Observable로 변환하기

3-1) UpdateAsObservable

 - 스트림을 생성하고 게임 오브젝트나 클래스에 연결한다. Monobehaviour의 Update를 스트림으로 만든 것과 같다.

 - gameObject의 Destroy 시점에 OnCompleted가 발생한다.

var obervable2 = gameObject.UpdateAsObservable(); // 오브젝트에 붙이기
var obervable1 = this.UpdateAsObservable(); // 클래스에 붙이기

 

3-2) Observable.EveryUpdate

 - 정적 Update 스트림을 생성한다.

 - 수동으로 해제 시점을 지정하지 않으면 무한하게 감시한다.

var observable = Observable.EveryUpdate();

 

3-3) ObserveEveryValueChanged

 - 특정 값이 변할 때를 감지한다.

 - 한 프레임 내에서 여러 번의 변화는 인지하지 못하며, 매 프레임 사이에 대한 변화만 감지한다.

   (즉 매 프레임마다 검사하는 Observable이 생성된다)

 - 대상이 Dispose될 때 OnCompleted가 호출된다.

button.ObserveEveryValueChanged(x => x.colors)
      .Subscribe(_ => Test());
        
 // 위를 UpdateAsObservable로 풀어서 써보면 아래와 같다.
this.UpdateAsObservable()
    .Select(_=>button1.colors)
    .DistinctUntilChanged()
    .Subscribe(_ => Test());

 

 

4. ReactiveProperty

 - reactiveProperty로 멤버변수를 선언하고, 이 값이 변할 때마다 스트림을 통해 OnNext 메시지가 발생한다.

 - 이를 이용하면 간단하게 돈이나 점수의 변화 등을 감지하고 유아이에 표시할 수 있다. 

 

ReactiveProperty를 선언하는 클래스

public class TimeData
{
    // 값이 변경되면 OnNext로 통지된다.
    private readonly ReactiveProperty<int> _timerReactiveProperty = new IntReactiveProperty(30);
    public ReadOnlyReactiveProperty<int> CurrentTime
        => _timerReactiveProperty.ToReadOnlyReactiveProperty();
}

값의 변화를 구독하는 클래스

public class MyTimerDisplay : MonoBehaviour
{
    [SerializeField] Text _timerText;
    TimerData _timerData = new TimerData();

    public void Start()
    {
        // ReactiveProperty를 구독한다.
        _timerData.CurrentTime.SubscribeToText(_timerText);
    }
}

 

 

 

 

 

댓글

Designed by JB FACTORY