[TIL][RxSwift] PublishSubject

Uno·2022년 1월 22일
0

RxSwift

목록 보기
4/9

Publish Subject

  • 결론

Publish Subject 를 구독한 이후의 값의 이벤트만 방출하는 서브젝트

상황을 하나 가정해보겠습니다.

currentUserName 이라는 데이터에는 사용자의 이름을 서버로부터 전달받고, 그 데이터를 UI에 전달합니다. 그래서 currentUserName에서 이벤트를 전달받을 수 있도록 PublishSubject 로 선언하겠습니다. 그리고 그 서브젝트를 바라보고 있다가 변경되면, 자신의 값을 변경할 데이터를 총 3 개 만들겠습니다.

  • titleLabel
  • profileLabel
  • userInfoLabel

(iOS에서 자주보일법한 네이밍이죠. UI와 데이터를 바인딩하는 것은 다른 글에서 자세히 설명하겠지만, 이번 예시는 데이터의 흐름과 서브젝트를 이해하기 위함이니 이미 배경지식이 있는 분들은 감안하고 읽어주시면 됩니다.)

먼저 이벤트 전달받고 그 데이터를 이벤트로 전달해줘야하므로 서브젝트를 하나 만들겠습니다.

let currentUserName = PublishSubject<String>()

그리고 이벤트를 전달하겠습니다.

currentUserName.onNext("Default UserName")

여기까지하시고 실행하면, 아무일도 일어나지 않습니다. 이유는 옵저버(구독자)가 없기 때문이죠. 이전에 설명했던 비유처럼, 신문사가 신문만 발행한다고 해서 사건 사고 에 대한 정보(이벤트)가 전달되지는 않는 것처럼요.

이벤트를 전달받아서 처리하기 위해서 구독자를 선언하겠습니다.

let titleLabel 
= currentUserName
	.subscribe { print("titleLabel: \($0)") }
	.disposed(by: bag)

여기서 실행해봐도 아무일도 일어나지 않습니다.

분명 서브젝트를 생성했고, 서브젝트와 옵저버를 연결하기 위해서 subscribe메소드를 사용했는데도 말이죠. 이유는 publishSubject의 특성에 있습니다. publishSubject는 구독한 시점 이후의 이벤트만 전달합니다. 서브젝트 중에서 가장 노멀한 서브젝트입니다.

이벤트를 받기 위해서 구독 이후에 서브젝트에서 next 이벤트를 방출하겠습니다.

currentUserName.onNext("Uno")

결과

titleLabel: next(Uno)

콘솔에서 위 결과가 나올것입니다.

이제 데이터를 입력받아서 이런식으로 데이터를 받을 수 있고 지금 print문으로 처리한 부분에 UI를 넣어주면 UI가 업데이트 되겠죠?

(물론 UI 업데이트는 다른 연산자를 활용합니다. 이후 다른 글에서 설명할 예정입니다.)

다른 옵저버를 추가해보겠습니다.

let profileLabel 
= currentUserName
	.subscribe { print("profileLabel: \($0)") }

currentUserName.onNext("Moya")

currentUserName.onCompleted()

let userInfoLabel
= currentUserName
	.subscribe { print("userInfoLabel: \($0)") }
	.disposed(by: bag)

위에서 했던것처럼 profileLabel을 추가한 이후에 moya를 이벤트로 넘겼습니다. 달라진 점이라면 그 이후에 completed이벤트를 전달하고 있습니다. 그러면 아래 있는 userInfoLabel은 이벤트가 어떻게 될까요?

결과는 아래와 같습니다.

titleLabel: next(Uno)
titleLabel: next(Moya)
profileLabel: next(Moya)
titleLabel: completed
profileLabel: completed
userInfoLabel: completed

completed 이후에는 다른 이벤트를 받지 못합니다. 이름 그대로 종료되었다는 뜻이죠.

소스코드에서 다음과 같이 Event에 대한 처리를 아래와 같이 하고 있습니다.

extension Event {
    /// Is `completed` or `error` event.
    public var isStopEvent: Bool {
        switch self {
        case .next: return false
        case .error, .completed: return true
        }
    }
  
  ...
  
}

isStopEvent가 true를 리턴하게되면, 더이상 이벤트를 전달하지 않게 됩니다. 에러도 마찬가지로 동작합니다.

이처럼 PublishSubject는 자신도 이벤트를 받아야하면서, 추가한 이후에 이벤트를 전달하는 다른 서브젝트에 비해 단순한 데이터흐름이 발생한 경우에 주로 사용하곤 합니다.

profile
iOS & Flutter

0개의 댓글