본문 바로가기

RxSwift

[RxSwift] Subject에 대한 개념

반응형

Subject는 RxSwift를 사용하여 프로젝트를 진행할 경우 많이 접하게 될 항목들입니다.

 

여기에서는 Subject 자체에 대한 설명만 하려 합니다. 

 

Subject는 PublishSubject, BehaviorSubject, ReplaySubject세 가지 종류가 있으며, 이에 대한 차이점은 ReactiveX 공식 사이트를 참고하시면 좋을 것 같습니다.

 

 

 

ReactiveX - Subject

If you have a Subject and you want to pass it along to some other agent without exposing its Subscriber interface, you can mask it by calling its asObservable method, which will return the Subject as a pure Observable. See Also

reactivex.io

 

Subject란 무엇일까요? 먼저 Subject의 특징을 통해 알아보겠습니다.

  • Subject란 Observable이자 Observer의 성격을 지니고 있습니다.

  • Subject는 동적으로 값을 발행할 수 있습니다.

  • Subject는 구독하고 있는 "Observer들"에게 값을 발행할 수 있습니다. (multicast 방식)

Subject는 ObservableType프로토콜을 채택하고 있는 Observable을 상속하고 있으며, ObserverType프로토콜을 채택하고 있습니다.

이는 Subject가 Observable이자 Observer 라는 것을 의미합니다. Subject 중 하나인 PublishSubject 코드를 보면 다음과 같습니다.

 

Observable이면서 Observer인 Subject의 성격으로 브릿지 역할을 할 수 있습니다.

 

관찰자(Observer)의 성격을 지니고 있기 때문에, 하나 이상의 Observable을 구독할 수 있습니다.

그리고 Observable이기 때문에 이벤트를 발행할 수 있습니다.

 

쉽게 말하면, 이벤트를 발행(emit)할 수도 있으며 구독(subscribe)할 수도 있다는 의미입니다.

이와 같은 특성을 이용하여, view의 UserInteraction을 viewModel의 Subject가 구독하고,

구독을 통해 발행된 값을 바탕으로 viewModel에서 비즈니스 로직을 거쳐 가공된 데이터를 View가 구독함으로써 연결다리 역할을 할 수 있습니다.

 

이외에도 ObserverType 프로토콜을 채택함으로써 동적으로 이벤트를 발행할 수 있습니다.

 

위의 on 메서드를 통해서 이벤트를 발행할 수 있습니다.

이벤트를 살펴보겠습니다.

 

Subject는 ObserverType이기 때문에 on 메서드를 콜 할 수 있고, 이벤트를 next, error, compete로 발행할 수 있다는 것을 알 수 있습니다.

 

Subject가 이벤트를 발행하고 이를 구독하는 것에 대한 설명을 하겠습니다.

일반적인 Observable과 Subject는 모두 구독(subscribe)할 수 있습니다. 하지만 차이점이 있습니다.

 

Subject는 multicast 방식이기 때문에 여러 개의 Observer에게 이벤트를 발행할 수 있습니다.

하지만 Single을 포함한 일반적인 Observable은 unicast 방식으로 하나의 observer에게만 이벤트를 발행합니다. 다음 그림을 보면 직관적으로 이해가 될 것입니다.

 

 

그러면 하나의 Observable은 하나의 Observer만 지니고 있다는 것은 여러 번 구독을 할 수 없다는 의미일까요?

이어서 부연 설명을 하도록 하겠습니다.

 

일반적인 Observable은 어떠한 상태도 가지지 않습니다. 따라서 모든 Observer가 구독하게 되면 그때마다 새로 생성(create)하여 발행하는 과정을 거치게 됩니다.

 

하지만 Subject의 경우 Observer들의 정보를 저장하고 발행된 이벤트를 모든 Observer에게 제공하게 됩니다.

예시를 통해 unicast와 multicast의 차이를 살펴보겠습니다.

 

randomNumGenerator1를 두 번 구독하여 테스트를 진행했는데, next에 다른 결괏값이 출력되었습니다.

이는 Observer가 해당 Observable에 대해 독자적으로 실행하기 때문입니다.

 

구독을 진행할 때마다 create가 호출되는 것을 의미하며, 따라서 결괏값이 그때그때 새로 생성된 값으로 할당됩니다.

 

다음으로 Subject를 통해 multicast를 알아보겠습니다.

 

비슷한 방식으로 PublishSubject인 randomNumGenerator2를 두 번 구독하여 테스트한 결과로 같은 값이 공유되어 받을 수 있었습니다.

 

이처럼 Subject는 observer들에게 발행된 이벤트를 알려주는 것이라고 할 수 있습니다. 

 

어떤 식으로 observer들에게 알려줄 수 있는지 자세히 알아보겠습니다. (PublishSubject를 예로 설명하도록 하겠습니다.)

 

Subject는 세 가지 종류가 있는데, ObserverType 프로토콜의 on 메서드가 동일한 방식으로 구현되어 있습니다.

 

Notifies all subscribed observers about next event.

위 주석을 해석하면 구독 중인 Observer들에게 next 이벤트를 전달한다는 것을 알 수 있습니다.

 

더불어 Subject는 private 프로퍼티로 Observer들을 가지고 있으며, 이 프로퍼티를 이용하여 구독 중인 Observer 정보를 관리한다는 것을 알 수 있습니다.

 

위의 on 메서드가 _observers에게 어떤 방식으로 next를 전달하는 알아보겠습니다.

 

on 메서드 하단에 _synchronized_on메서드를 호출하고 있습니다.

 

구현부는 위와 같은데, 정상적인 상황일 경우, _observers를 반환합니다.

 

 

따라서 위의 dispatch 메서드의 첫 번째 인자는 구독 중인 Observer들이 들어가며, 그 Observer들에게 event 발행을 하는 것을 알 수 있습니다.

 

그럼 언제 Observer를 Subject에 추가할 수 있을까요?

 

생각해보면 구독(subscribe)을 진행하는 경우에 추가가 된다는 것을 알 수 있습니다. (구독할 경우에만 Observer를 알 수 있기 때문입니다.)

 

구독하는 과정을 살펴보겠습니다.

 

ObservableType 프로토콜을 확장하여 구현된 subscribe 메서드는 Observable과 Subject에서 사용됩니다.

 

 

여기서 주목해야 할 부분은 Disposable을 create 하고 return 하는 과정에서 불리는

self.asObservable().subscribe(observer) 함수입니다.

 

위에서 설명했듯이 Obsevable 상속을 통해 ObservableType protocol을 자연스럽게 채택했으며 각 Subject는 그 안에 override를 통해 subscribe 함수를 구현해 놓고 있음을 확인할 수 있습니다.

 

위 메서드가 호출되면서 각 Subject 마다 다른 구현부를 가진 _synchronized_subscribe(observer)가 호출됩니다.

 

정상적인 상황일 경우 let key = _observers.insert(observer.on)를 통해 _observers에 Observer를 추가한 key라는 변수를 만들고, subscription을 만들어 리턴하게 됩니다. 돌아와서 다음 코드를 다시 보며 설명하겠습니다.

 

위 과정을 거치며 Subject의 모든 Observer들에 대한 subscription이 담기게 되며 (일반적인 Observable일 경우 단일 observer에 대한 subscription) .on이 실행될 경우 모든 Observer가 이벤트를 받을 수 있도록 할 수 있습니다.

반응형