UniRX 배우기 3) 스트림의 구독과 종료시점

참고 : 데브루키 UniRX시작하기
https://www.slideshare.net/agebreak/160409-unirx

 

 

 

스트림의 구독(Subscribe)

 - 스트림은 Subscribe 된 순간에 생성된다. (LINQ에서도 존재하는 특성)

 - OnError나 OnComplete가 발생하면 구독이 종료된다.

 - Subscribe는 오버로드로 정의되어있어 선택적으로 Action을 추가할 수 있다.

   (기본형은 일반적인 메시지인 OnNext만 Action을 할당하게 되어있다.)

 

 

 

구독의 종료 시점

구독은 OnCompleted()가 호출될 때까지 지속된다.

 

 

1) 게임 오브젝트에 연결된 경우

 - ObservableTriggers는 연결된 게임 오브젝트가 Destroy될 때 OnCompleted를 호출함.

 

2) 정적 스트림을 구독한 경우

 - Observable.EveryUpdate 등과 같이 정적스트림은 자동으로 중지되지 않으며, 수동으로 관리해야 한다.

Observable.EveryUpdate().Subscribe(x => Debug.Log(x));

 - 정적으로 스트림을 만든 경우에도 AddTo로 오브젝트에 연결시켜놓으면, 오브젝트가 삭제될 때 Dispose된다.

Observable.IntervalFrame(30).Subscribe(x => Debug.Log(x)).AddTo(this);

 

3) 오퍼레이터를 통해 완료 조건을 설정한 경우

 - TakeWhile, TakeUntil, TakeUntilDestory 등과 같이 조건을 만족시키면 OnCompleted가 호출된다.

 - 그러나 Repeat를 같이 사용한 경우 무한 루프가 발생할 수 있으니 주의할 것.

 

4) 감시 대상이 일반 C# 객체일 경우

 - GC에 의해 Dispose()될 때 OnCompleted가 호출됨

 

5) 직접 Dispose된 경우

 - IDisposable 인터페이스의 Dispose()를 호출할 경우 직접 구독을 종료하게 된다.

 - 이때는 OnCompleted()가 호출되지 않으니 주의할 것.

IDisposable disposable = button1.onClick
    .AsObservable()
    .Subscribe(_ => text.text = "클릭");
    
disposable.Dispose();

 

 

이미 Completed가 호출된 Subject

이미 OnCompleted()가 통지된 Subject는 재사용이 불가능하며,

Subscribe를 호출해도 바로 OnCompleted가 발행된다.

IEnumerator Start()
{
    Subject<int> mySubject = new Subject<int>();
    mySubject.AsObservable()
        .Subscribe(n => Debug.Log(n),
        () => Debug.Log("종료됨"));

    mySubject.OnNext(0);
    yield return new WaitForSeconds(0.5f);
    mySubject.OnCompleted();
    yield return new WaitForSeconds(0.5f);
    mySubject.AsObservable()
        .Subscribe(n => Debug.Log(n),
        () => Debug.Log("종료됨"));
    yield return new WaitForSeconds(0.5f);
    mySubject.OnNext(1);
}

 

 

특정 구독만 종료하기

 - 하나의 Subject에 여러개의 구독이 실행되고 있을 경우 Subject.OnCompleted()를 통해 전체 구독을 종료할 수 있다.

 - 만일 특정 구독만 종료하고 싶다면 IDisposable 인터페이스의 Dispose()를 실행하면 된다.

 - 단, 이 경우 OnCompleted()가 호출되지 않는다.

public Subject<int> mySubject = new Subject<int>();

IEnumerator Start()
{
    IDisposable disposalA = mySubject.Subscribe(
        _ => Debug.Log("A"), 
        () => Debug.Log("A Completed"));

    IDisposable disposalB = mySubject.Subscribe(
        _ => Debug.Log("B"),
        () => Debug.Log("B Completed"));

    StartCoroutine(MyCoroutine());
    yield return new WaitForSeconds(1f);
    disposalA.Dispose();
}

IEnumerator MyCoroutine()
{
    while(true)
    {
        yield return new WaitForSeconds(0.8f);
        mySubject.OnNext(0);
    }
}

 - 위 예제에서 mySubject.Dispose()시 -> 두 개의 구독이 OnCompleted없이 종료

 - mySubject.OnCompleted()시 -> 두 개의 구독이 OnCompleted를 발생시키며 종료

mySubject.OnCompleted();

 

 

 

댓글

Designed by JB FACTORY