[UniRx 입문 강좌 1] 개념 및 기본 사용법 소개
[UniRx 입문 강좌 2] UniRx 의 핵심, Subject 와 Observable 사용 방법
[UniRx 입문 강좌 4] Operator 활용(1) - Where & Select & SelectMany 사용법
[UniRx 입문 강좌 5] Operator 활용(2) - 다양한 오퍼레이터 소개
[UniRx 입문 강좌 6] 코루틴(Coroutine) 과 UniRx 연동
1. IObserver & IObservable 인터페이스
지난 강의에서 Subject 에 대해 설명하면서 IObserver 인터페이스를 구현하는 과정에서 아래 참고 이미지를 사용했었다.
이번 강좌에서는 IObserver 의 인터페이스인 OnNext 와 OnError, OnComplete 에 대해 좀더 자세히 짚고 가겠다.
그만큼 UniRx 를 사용하면서 자주 보게 될 메세지 들이기 때문이다.
실제 IObserver 와 IObservable 인터페이스 클래스 소스 코드를 보면 위 도표와 똑같이 각각 3개, 1개의 메소드만 정의 되어 있다.
UniRx 에서 사용되는 이벤트 메세지는 이 3가지를 이용해 처리 된다.
- OnNext : 일반적인 이벤트 발생 시 통지
- OnError : 스트림 처리 중 예외(Exception)발생 시 통지
- OnComplete : 스트림 종료 통지
Subscribe 메서드는 이 메세지들 중 원하는 것만 받아서 처리할 수 있게각 상황별로 오버로드 되어 있다.
Subscribe 오버로드 | 기능 |
Subscribe(IObserber observer) | 기본형 |
Subscribe() | 모든 메시지를 무시한다 |
Subscribe(Action onNext) | OnNext 만 처리 |
Subscribe(Action onNext, Action onError) | OnNext & OnError |
Subscribe(Action onNext, Action onCompleted) | OnNext & OnCompleted |
Subscribe(Action onNext, Action onError, Action onCompleted) | OnNext & OnError & OnCompleted |
자, 그럼 이 메세지 들이 어떻게 동작하는지 살펴 보자.
2. OnNext
UniRx 에서 이벤트를 통지할 때 대부분 이 OnNext 메세지를 사용하게 될 것이다.
기본 사용에 있어서는 이 OnNext 만 사용해도 큰 문제가 없다.
예제와 같이 OnNext 가 호출 될 때마다 정수형 이벤트를 Subscibe 에 통지해 준다.
3. OnError
OnError 메세지는 위에서 설명했듯이 스트림 처리 중 예외(Exception) 이 발생하면 통지된다.
에러 처리가 필요 없다면 OnNext 와 달리 생략도 가능하다.
또한 OnError 메세지가 Subscribe 에 도달한다면 이 스트림은 그 시점에서 바로 구독이 종료 된다는 점을 명심하자.
간단한 샘플 코드를 살펴보자.
스트림을 처리하는 중에 예외가 발생하자 Subscribe에 OnError 메세지가 통지 되고 스트림의 구독이 종료 되어 이후에 발생한 OnNext("4") 는 처리 되지 않았다.
만약 예외가 발생한 경우 그에 대한 처리를 해주고 다시 구독을 이어나가고 싶다면 어떻게 해야 할까.
이전 예제와 달리 예외가 발생해도 마지막 까지 Subscribe 에 통지를 진행한다.
다른 점은 예외가 발생한 Select 와 Subscribe 사이에 OnErrorRetry 가 추가된 점인데 이 OnErrorRetry 는 예외를 중간에서 Catch 한 후 스트림을 재구축 (Subject 에 IObserver 를 다시 등록) 하여 구독을 계속 이어가게 해준다.
이로 인해 Subscribe 의 OnError 가 발생하지 않게 되는 것이다.
이 예외 처리와 관련한 몇개의 오퍼레이터가 있다.
Operators | 기능 |
Retry | OnError 발생 시 다시 Subscribe 한다 |
Catch | OnError 발생 시 예외 처리 후 다른 스트림으로 대체한다 |
CatchIgnore | OnError 발생 시 예외 처리 후 OnError 를 무시하고 OnCompleted 로 대체한다 |
OnErrorRetry | OnError 발생 시 예외 처리 후 Subscribe 한다 (시간 지정 가능) |
4. OnCompleted
OnCompleted 는 스트림이 완료 되었으므로 이후로는 메세지를 발행하지 않는다 라는 사실을 통지하는 메세지이다.
OnError 와 마찬가지로 Subscribe 에 OnCompleted 가 통지되면 해당 스트림은 바로 구독이 종료 된다.
이를 이용해 스트림을 파기하려는 시점에 OnCompleted 를 발행하여 구독을 종료 시킬 수 있다.
이렇게 구독이 종료된 Subject 는 재사용이 불가능 하며 Subscribe 를 호출해도 바로 onCompleted 가 발생하게 된다.
OnCompleted 를 발생 시키면 스트림의 구독이 완전히 중단되는 것을 확인 할 수 있다.
5. Dispose
위의 IObserver 의 OnNext, OnError, OnCompleted 와 마찬가지로 Subject 가 구현하고 있는 IObservable 의 "IDispose" 에 대해 알아보자.
Subscribe 의 반환값인 IDisposable 은 가비지컬렉터가 관리하지 않는 리소스를 해제해 주기 위한 C#의 기본 인터페이스이다. (IDisposable.Dispose() 로 해제)
Subscribe 가 완료 될 때 이 IDisposable 을 반환 한다는 것은 곧 이 IDisposable 의 Dispose 를 실행하면 스트림의 구독이 종료 된다는 뜻이다.
간단한 사용예를 보자.
이와 같이 Dispose 를 호출하여 이 스트림의 구독을 중단 할 수 있다.
단, OnCompleted 이벤트가 아니라 Dispose() 로 구독을 종료했을 경우 OnCompleted 를 전달하지 않는다는 점을 주의해야 한다.
또 한가지, OnCompleted 는 호출하는 Subject 의 모든 스트림의 Subscribe 가 중단 되지만 Dispose 는 Subject 의 스트림 중 원하는 한개의 스트림만 구독을 중단 할 수 있다.
아래 샘플을 참고하자.
6. 스트림의 라이프 사이클(Life Cycle)
스트림은 편리하게 사용할 수 있지만 객체의 잦은 생성과 삭제가 퍼포먼스에 큰 영향을 미치는 유니티 특성 상 특히 수명 관리에 신경을 써야 한다.
기본적으로 스트림은 Subject 에 포함 되는 일부 또는 그 자체 라고 볼 수 있으며 Subject 가 Destory 되면 스트림도 파기 된다.
하나하나의 스트림은 Subscribe 가 끝단에 위치하여 흘러온 데이터를 처리하게 되며 이 각각의 스트림 들은 Subject 에 등록 되어 있다.
즉, Subject 가 파기되지 않고 남아있다면 각각의 스트림들도 살아있다는 뜻이 된다.
때문에 스트림이 참조하고 있는 오브젝트가 스트림보다 먼저 Destory 되어 버리면 해당 스트림의 처리는 정상적으로 이루어질 수 없음에도 여전히 살아남아 NullReferenceException 을 일으키거나 메모리릭 등 성능 저하와 치명적인 오류를 발생하는 원인이 될 수 있다.
하지만 사용될 오브젝트가 런타임에서 결정되거나 파기 타이밍을 매번 코딩하는 단계에서 확인하기 힘든 경우가 많기 때문에 스트림에서 일일이 오브젝트를 검사하는 것도 쉽지 않은 일이다.
이런 경우 가장 손쉽게 처리할 수 있는 방법은 AddTo 오퍼레이터를 사용하는 것이다.
AddTo 오퍼레이터에 GameObject 의 인스턴스를 지정하면 해당 인스턴스가 Detroy 되는지를 감시하여 자동으로 Dispose 를 호출하여 구독을 중단 시켜 준다.
[UniRx 입문 강좌 4] Operator 활용(1) - Where & Select & SelectMany 사용법
댓글