Lifetime

OnCompleted는 언제 호출 될까요?

Subscription 수명주기 관리는 UniRx를 사용할 때 고려해야 할 매우 중요한 내용입니다.

ObservableTriggers는 연결된 GameObject가 파괴될 때 OnCompleted를 호출합니다. 다른 정적 생성기 메서드 (Observable.Timer, Observable.EveryUpdate 등)는 자동으로 중지되지 않고 해당 구독을 수동으로 관리해야 합니다.

Rx는 IDisposable.AddTo와 같은 몇 가지 helper 메서드를 제공하므로 한 번에 여러 구독을 처리할 수 있습니다.

// CompositeDisposable is similar with List<IDisposable>, manage multiple IDisposable
CompositeDisposable disposables = new CompositeDisposable(); // field

void Start()
{
    Observable.EveryUpdate().Subscribe(x => Debug.Log(x)).AddTo(disposables);
}

void OnTriggerEnter(Collider other)
{
    // .Clear() => Dispose is called for all inner disposables, and the list is cleared.
    // .Dispose() => Dispose is called for all inner disposables, and Dispose is called immediately after additional Adds.
    disposables.Clear();
}

GameObject가 Destroy 될 때 자동으로 Dispose하려면 AddTo (GameObject/Component)를 사용하기 바랍니다.

void Start()
{
    Observable.IntervalFrame(30).Subscribe(x => Debug.Log(x)).AddTo(this);
}

AddTo를 사용하면 자동으로 Dispose를 호출할 수 있습니다. 그러나 파이프 라인에서 특별한 OnCompleted 호출이 필요한 경우에는 TakeWhile, TakeUntil, TakeUntilDestroyTakeUntilDisable을 대신 사용하기 바랍니다.

Observable.IntervalFrame(30).TakeUntilDisable(this)
    .Subscribe(x => Debug.Log(x), () => Debug.Log("completed!"));

Repeat 연산자를 이용해서 이벤트를 처리하는 경우 무한 루프가 발생할 수 있으므로 주의해야 합니다.

using UniRx;
using UniRx.Triggers;

public class DangerousDragAndDrop : MonoBehaviour
{
    void Start()
    {
        this.gameObject.OnMouseDownAsObservable()
            .SelectMany(_ => this.gameObject.UpdateAsObservable())
            .TakeUntil(this.gameObject.OnMouseUpAsObservable())
            .Select(_ => Input.mousePosition)
            .Repeat() // dangerous!!! Repeat cause infinite repeat subscribe at GameObject was destroyed.(If in UnityEditor, Editor is freezed)
            .Subscribe(x => Debug.Log(x));
    }
}

UniRx의 RepeatSafe 연산자를 사용하면 반복하는 이벤트를 안전하게 처리할 수 있습니다.

RepeatSafe는 "OnComplete"가 반복해서 호출되는 경우 스트림을 중지시킵니다. RepeatUntilDestroy (gameObject / component), RepeatUntilDisable (gameObject / component)는 해당 GameObject가 Destroy/Disable 된 경우 이벤트 처리를 중지합니다.

this.gameObject.OnMouseDownAsObservable()
    .SelectMany(_ => this.gameObject.UpdateAsObservable())
    .TakeUntil(this.gameObject.OnMouseUpAsObservable())
    .Select(_ => Input.mousePosition)
    .RepeatUntilDestroy(this) // safety way
    .Subscribe(x => Debug.Log(x));

UniRx는 FromEvent/Subject/ReactiveProperty/UnityUI.AsObservable 등의 Observable에 대해서는 예외(exception)가 발생하는 경우에도 이벤트의 처리를 계속할 수 할 수 있습니다.

아래 예제는 버튼 클릭 이벤트가 발생한 경우 주어진 URL로부터 WWW 객체를 다운받는 코드입니다. 만약 WWW의 Get을 완료하기 전에 예외가 발생하더라도 버튼 객체는 이와 관계 없이 클릭 이벤트를 계속 관찰하는 것이 가능합니다.

button.OnClickAsObservable().Subscribe(_ =>
{
    // If throws error in inner subscribe, but doesn't detached OnClick event.
    ObservableWWW.Get("htttp://error/").Subscribe(x =>
    {
        Debug.Log(x);
    });
});

이 방법을 이용한 처리는 사용자 이벤트 처리에 유용한 방법입니다.

모든 클래스 인스턴스는 ObserveEveryValueChanged 연산자를 사용해서 매 프레임마다 값의 변화를 관찰할 수 있습니다:

// watch position change
this.transform.ObserveEveryValueChanged(x => x.position).Subscribe(x => Debug.Log(x));

이 방법은 관찰하는 타겟 객체가 GameObject인 경우 특히 유용합니다. 관찰하는 GameObject가 Destroy되면 OnCompleted를 호출하고 관찰을 중지하비다. 타겟 객체가 일반적인 C# 클래스 인스턴스인 경우에는 GC에서 OnCompleted를 호출합니다.

results matching ""

    No results matching ""