IObservable의 "IDisposable"를 설명하겠다.
public interface IObservable<T>
{
IDisposable Subscribe(IObserver<T> observer);
}
IDisposable는 C#에서 제공하는 인터페이스이며, "리소스 해제"를 실시할 수 있도록 하기 위한 메서드 "Dispose()"를 단지 1개 가지고 있는 인터페이스다.
Subscribe의 반환값이 IDisposable로 이라는 것은 즉 Subscribe 메서드가 돌려주는 IDisposable의 Dispose를 실행하면 스트림의 구독을 종료 할 수 있다는 것이 된다.
다음 코드를 통해 예시를 볼 수 있다.
var subject = new Subject<int>();
// IDispose 저장
var disposable = subject.Subscribe(x => Debug.Log(x), () => Debug.Log("OnCompleted"));
subject.OnNext(1);
subject.OnNext(2);
// 구독종
disposable.Dispose();
subject.OnNext(3);
subject.OnCompleted();
실행 결과
1
2
위의 코드는 구독을 Dispose를 호출하여 도중에 중지하는 예다.
따라서 Dispose를 호출하여 구독을 언제라도 중단 할 수 있다.
여기서 주의해야 할 것은 Dispose()를 실행해서 구독이 중단되도 OnCompleted가 발행되는 것은 아니다 라는 점이다. 구독 중단 처리를 OnCompleted에 사용하는 경우, Dispose에서 정지시켜 버리면 실행되지 않으므로 주의하시기 바란다.
또한 다음 코드를 통해서 특정 스트림만 수신을 거부 할 수도 있다.
var subject = new Subject<int>();
// IDispose 저장
var disposable1 = subject.Subscribe(x => Debug.Log("스트림1:" + x), () => Debug.Log("OnCompleted"));
var disposable2 = subject.Subscribe(x => Debug.Log("스트림2:" + x), () => Debug.Log("OnCompleted"));
subject.OnNext(1);
subject.OnNext(2);
// 스트림1만 구독종료
disposable1.Dispose();
subject.OnNext(3);
subject.OnCompleted();
실행 결과는 다음과 같다.
스트림1 : 1
스트림2 : 1
스트림1 : 2
스트림2 : 2
스트림2 : 3
2 : OnCompleted
다음 코드는 특정 Subscribe의 Dispose를 호출하여 그 구독만 중지시키고 있는 예다.
OnCompleted를 실행하면 모든 스트림을 구독 종료하게되지만 Dispose를 사용하면 일부 스트림만 종료시킬 수 있다.
UniRx를 사용하는데 있어서 특히 조심하지 않으면 안되는 것이 스트림의 라이프 사이클이다.
객체가 자주 출현과 삭제를 반복하는 Unity에서는 특히 이것을 의식하지 않으면 퍼포먼스 저하나 에러에 의한 오동작을 일으키게 된다.
기본적으로, 스트림의 실체는 "Subject"이며 Subject가 파기되면 스트림도 파기된다.
Subject가 내부에 유지하는 "호출 함수 목록( 및 그 함수에 연관된 메소드 체인)"로, Subject가 스트림을 관리하는 것입니다.
Subject가 파기되면 스트림도 모두 파기된다. 반대로 말하면, Subject가 남아있는 한 스트림은 계속 실행 된다. 스트림이 참조하고 있는 객체를 스트림보다 먼저 버리고 방치해 버리면 뒤에서 스트림이 계속 동작 상태가 되기 때문에 성능 저하를 일으키거나 메모리 누수가 발생하거나 NullReferenceException을 발생시켜 게임을 정지시킬 가능성도 있다.
스트림의 수명 관리는 세심한 주의를 기울여야 된다. 사용이 끝나면 반드시 Dispose를 호출하거나 OnCompleted를 발행하는 습관을 가져야한다.
출처 : https://tech.lonpeach.com/2019/11/06/UniRx-Getting-Started-2