Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Archives
Today
Total
관리 메뉴

iOS 개발 노트

🪴RxSwift: Subject에 대해서 본문

RxSwift

🪴RxSwift: Subject에 대해서

Daeyun Kwon 2024. 8. 5. 00:23

Subject

Observable과 Observer의 역할을 모두 할 수 있는 친구이다.
즉 Observable로써 이벤트를 방출(emit)할 수도, Observer로써 어떤 이벤트를 구독(Subscribe)하여 무엇인가 처리하는 것도 할 수 있는 것이다.

 

Subject는 4가지 종류로 구분된다.

  • Publish Subject
  • Behavior Subject
  • Replay Subject
  • Async Subject

PublishSubject

  • 값 저장 없음.
  • 구독자가 구독을 시작하기 전에 방출된 값은 받을 수 없음. → 저장된 값이 없으니깐!
  • 구독자가 구독을 시작하면 그 이후부터 방출된 값을 받을 수 있음.
  • 구독자가 이벤트를 수신하기 시작한 이후의 이벤트만 다루고 싶을 때 유용함

생성 방법:

제네릭을 이용해 방출할 데이터의 타입을 표현해주어야 한다.

let myPublishSubject = PublishSubject<Int>()

 

이벤트 방출:

onNext 메서드를 통해 이벤트를 방출할 수 있다.
인자로 전달된 값이 바로 방출될 데이터의 값이며, 구독자는 해당 값을 전달받는다. 

myPublishSubject.onNext(1)
myPublishSubject.onNext(2)

 

구독:

onNext 메서드를 통해 이벤트가 방출될 때마다 bind 구문이 실행되며, 전달받은 이벤트의 데이터 값을 활용 가능하다.

myPublishSubject
   .bind { value in
       print(value)
   }
   .disposed(by: disposeBag)

 

PublishSubject는 구독한 시점 이후부터만 방출된 이벤트를 구독자가 받고 처리하는 게 가능하다.

다음 화면을 보면 구독 이전에 발생한 이벤트는 무시되어 처리되지 않은 모습이 확인 가능하다.

 

이벤트 방출 시점을 구독 이후로 변경해보면,
구독자에게 이벤트 데이터 값이 전달되어 이벤트 처리가 성공된 모습을 확인해 볼 수 있다.


BehaviorSubject

  • 값 저장 있음.
  • 구독자가 구독을 시작하면 현재 저장된 값을 즉시 방출해서 받을 수 있음
  • 구독자가 구독을 시작하면, 가장 최근의 값을 즉시 전달받음

생성 방법:

제네릭을 이용해 데이터 타입을 표현해줄 수 있으며, value 인자에 초기값을 지정해주어야 한다.

let myBehaviorSubject = BehaviorSubject<String>(value: "AAA")

 

이벤트 방출:

onNext 메서드를 통해 이벤트를 방출할 수 있다.
인자로 전달된 값이 바로 방출될 데이터의 값이며, 구독자는 해당 값을 전달받는다. 

myBehaviorSubject.onNext("사과")

 

구독:

onNext 메서드를 통해 이벤트가 방출될 때마다 bind 구문이 실행되며, 전달받은 이벤트의 데이터 값을 활용 가능하다.

myBehaviorSubject
    .bind { value in
       print(value)
    }
    .disposed(by: disposeBag)

 

BehaviorSubject는 초기값을 이용해 구독 시 바로 데이터를 전달받아 처리하는 게 가능하다.

 

구독 시작 전에 이벤트를 방출하면 어떻게 될까?

BehaivorSubject는 가장 최근에 방출한 데이터 값인 "BBB"를 가지게 된다.

그리고 구독을 시작하게 되면 BehaivorSubject가 가지고 있는 가장 최신 값인 "BBB" 데이터 값을 통해 이벤트 처리가 되는 모습을 확인해 볼 수 있다.


ReplaySubject

  • 값 저장 있음
  • bufferSize 만큼 메모리에 이벤트(방출할 값)를 가지고 있음
  • 구독자가 구독을 시작하면 bufferSize 만큼 가지고 있던 모든 이벤트를 모두 전달함
  • 오류가 발생하더라도 메모리에 보유하고 있던 이벤트(방출할 값)을 emit 하고 error를 notification 함

생성 방법:

제네릭을 이용해 데이터 타입을 표현해줄 수 있으며, create 메서드를 이용해 버퍼 사이즈를 설정해주어야 한다.

let myReplaySubject = ReplaySubject<String>.create(bufferSize: 3)

 

이벤트 방출:

이전 Subject들과 동일하게 onNext 메서드를 통해 이벤트를 방출할 수 있다.

myReplaySubject.onNext("사과")

 

구독:

이전 Subject들과 동일하게 onNext 메서드를 통해 이벤트가 방출될 때마다 bind 구문이 실행되며, 전달받은 이벤트의 데이터 값을 활용 가능하다.

myReplaySubject
    .bind { value in
       print(value)
    }
    .disposed(by: disposeBag)

 

구독을 시작하게 될 경우 버퍼 사이즈만큼 가지고 있던 이벤트들을 순차적으로 전달받아 처리하는 것을 확인해 볼 수 있다.

 

구독 전에 아무리 많은 이벤트가 방출되었다고 해도, 

구독 시에는 버퍼 사이즈 만큼의 최신 이벤트값만 받게 됨을 확인해 볼 수 있다.


AsyncSubject

  • 값 저장 있음
  • 구독자가 구독을 시작해도 이벤트를 방출하지 않음
  • .onCompleted()를 통해 completed 이벤트가 전달되지 전까지는 어떤 값도 전달하지 않음
  • completed 이벤트가 전달되면 그때 시점으로 가지고 있던 값(즉, 최신값)을 방출하고 끝남

생성 방법:

제네릭을 이용해 데이터 타입을 표현해주어야 한다.

let myAsyncSubject = AsyncSubject<String>()

 

이벤트 방출:

이전 Subject들과 동일하게 onNext 메서드를 통해 이벤트를 방출할 수 있다.

myAsyncSubject.onNext("받아라 이벤트")

하지만 이전 Subject들과는 다르게 구독한 곳에서 이벤트 처리까지는 진행하지 않는다.
이벤트 처리까지 진행하고 싶다면 onNext 다음에, 아래와 같이 onCompleted까지 실행해주어야 한다.

myAsyncSubject.onCompleted()

 

구독:

이전 Subject들과 다르게 onNext 메서드를 통해 이벤트가 방출될 때마다 bind 구문이 실행되지 않는다.
onCompleted를 실행한 시점에 가지고 있던 최근 이벤트 값을 통해 bind 구문이 실행된다. 

myAsyncSubject
    .bind { value in
        print(value)
        print("이벤트 받음")
    }
    .disposed(by: disposeBag)

 

 

onNext를 통해 이벤트를 방출해뒀지만, 구독한 시점에 이벤트 처리가 진행되지 않는 모습을 확인해 볼 수 있다.

 

onCompleted를 실행해주어야 가지고 있던 이벤트 처리가 진행되는 모습을 확인해 볼 수 있다.

 

Completed 이후에는 스트림이 종료되어 리소스 정리되었기 때문에,
더 이상 이벤트 방출 및 처리 역할을 수행하지 않는 모습을 확인해볼 수 있다.(마치 일회용 같은데, 자주 사용할지는 모르겠다..)

 

아무리 많은 이벤트를 방출 했더라도, Completed 실행 시에는 가장 최신 이벤트만 구독한 곳에서 처리되는 모습을 확인해 볼 수 있다.

 

'RxSwift' 카테고리의 다른 글

🪴ReactorKit에 대해서  (0) 2025.01.19