2021
04.29

 

코루틴과 UniRX는 상호 보완적으로 사용될 수 있다.

코루틴을 Observable로 변환하고, Observable을 코루틴으로 변환하며 혼용 사용이 가능하다.

 

 

1. 코루틴을 스트림으로 변환하기

 - 복잡한 처리를 코루틴에 숨기고 외부에서는 Observable로서 취급하는 것이 가능하다.

 - Cold 라서 Subscribe 될 때마다 새롭게 코루틴이 생성되고 시작한다.

 

1-1) Observable.FromCoroutine

 - 코루틴의 종료시간까지 대기하다, yield 된 시점에 OnCompleted()메시지가 호출된다.

 - 첫 번째 인수로는 코루틴을 취하고,

   두 번째 인수로는 yield시점에 OnNext()메시지를 발행하는지 여부 (기본 false이며, OnCompleted 직전에 한 번 발급)

public static IObservable<Unit> FromCoroutine(Func<IEnumerator> coroutine, bool publishEveryYield = false)
public static IObservable<Unit> FromCoroutine(Func<CancellationToken, IEnumerator> coroutine, bool publishEveryYield = false)

 - 사용 예시 : 코루틴이 종료되는 2초 후 문자열 출력

public void Start()
{
    Observable.FromCoroutine(ACoroutine, false)
        .Subscribe(_ => Debug.Log("OnNext"),
        () => Debug.Log("OnCompleted"));
}

private IEnumerator ACoroutine()
{
    Debug.Log("코루틴 시작");
    yield return new WaitForSeconds(2f);
    Debug.Log("코루틴 끝");
}

 - publishEveryYield = true 일 때의 결과 ( 매 yield 마다 OnNext가 발행 )

 

1-2) Observable.FromCoroutineValue<T>

 - 코루틴의 yield return 값을 OnNext 메시지로 받는다.

 - 리턴된 값이 형식 인수와 맞지 않으면 오류가 발생한다. (형 변환)

private void Start()
{
    Observable.FromCoroutineValue<string>(MyCoroutine)
        .Subscribe((n) => Debug.Log(n));
}

public IEnumerator MyCoroutine()
{
    while(true)
    {
        yield return new WaitForSeconds(1f);

        yield return "리턴";
    }
}

 

 

1-3) 코루틴에서 직접 메시지를 발행

 코루틴에 IObserver<T>를 넘겨서 코루틴 내부에서 메시지를 발행할 수 있다.

 

 - FromCoroutine의 매개변수는 IObserver<T>를 매개변수로 가지고, IEnumerator를 반환형으로 가지는 Func

   (즉 IObserver<T>를 매개 변수로 가진 코루틴을 호출하는 람다식)

public static IObservable<T> FromCoroutine<T>(Func<IObserver<T>, IEnumerator> coroutine)
public static IObservable<T> FromCoroutine<T>(Func<IObserver<T>, CancellationToken, IEnumerator> coroutine)

 - 코루틴 내에서는 매개변수로 받은 IObserver<T> 객체를 통해 원하는 타이밍에

   OnNext(T)와 OnCompleted()등을 호출하여 메시지를 보낼 수 있다.

public class MyClass
{
    public void Start()
    {
        Observable.FromCoroutine<int>(observer => MyCoroutine(observer, 0, 10))
            .Subscribe(count => Debug.Log(count));
    }

    private IEnumerator MyCoroutine(IObserver<int> observer, int startCount, int endCount)
    {
        int count = startCount;

        while (true)
        {
            yield return new WaitForSeconds(0.1f);
            observer.OnNext(++count);

            if (count >= endCount)
                observer.OnCompleted();
        }
    }
}

 

 

2. 스트림을 코루틴으로 변환하기

 - StartAsCoroutine를 사용하여 IObservable을 코루틴으로 변환할 수 있다.

 - 5.3 버전부터는 StartAsCoroutine()을 ToYieldInstruction으로 사용할 수도 있다.

public static Coroutine StartAsCoroutine<T>(this IObservable<T> source, CancellationToken cancel = default(CancellationToken))
public static Coroutine StartAsCoroutine<T>(this IObservable<T> source, Action<T> onResult, CancellationToken cancel = default(CancellationToken))
public static Coroutine StartAsCoroutine<T>(this IObservable<T> source, Action<Exception> onError, CancellationToken cancel = default(CancellationToken))
public static Coroutine StartAsCoroutine<T>(this IObservable<T> source, Action<T> onResult, Action<Exception> onError, CancellationToken cancel = default(CancellationToken))

 - OnCompleted를 호출할 때까지 yield return null을 계속 반복한다.

 - StartAsCoroutine에 전달된 함수는 OnCompleted를 호출할 때에 한 번만 실행되고 마지막 OnNext 값이 전달된다.

private void Start()
{
    StartCoroutine(MyCoroutine());
}

public IEnumerator MyCoroutine()
{
    Debug.Log("코루틴 시작");
    int result = 0;
    yield return Observable.Range(1, 10).StartAsCoroutine(n => result = n);
    Debug.Log($"결과값 :{result}");
}

 

 

 

COMMENT