[RxSwift] Subject와 Relay - (3)

728x90
반응형

 

 

 

 

Subject와 Relay의 개념에 대해 알아 보겠습니다.

 

지난 블로그Observable편에서 Observable이 무엇이고 어떻게 만드는지에 대해 배웠습니다.

이번장에선 Observable이자 Observer인 Subject의 개념에 대해 알아보도록 하겠습니다.

 

Subject란

좀 더 나아가 개발을 할때 실시간으로 Observable에 값을 추가하고 Subscriber를 할 수 있는 놈이 필요합니다.
이때 Observable이자 Observer인것을 Subject라고 합니다.

Observable + Observer = Subject라는 이 부분의 의미를 자세히 고민해보세요.
확실히 알고 넘어가야합니다.

 

이벤트를 외부에 전달해줄 경우에 사용해서, Delegate대신 사용하기도 합니다.

종류

  • PublishSubject
  • BehaviorSubject
  • ReplaySubject

 

PublishSubject

PublishSubject는 .completed, .error이벤트가 발생할때까지, 즉 종료될때까지 subscribe한 이후부터 이벤트를 방출 합니다.

let subject = PublishSubject<Int>()

let subjectOne = subject
    .subscribe(onNext: { (num) in
        print("subjectOne :",num)
    })

subject.onNext(1)
subject.onNext(2)

let subjectTwo = subject
    .subscribe(onNext: { (num) in
        print("subjectTwo :", num)
    })

subject.onNext(3)
subject.onNext(4)
subject.onNext(5)

/*
 subjectOne : 1
 subjectOne : 2
 subjectOne : 3
 subjectTwo : 3
 subjectOne : 4
 subjectTwo : 4
 subjectOne : 5
 subjectTwo : 5
 */

subject가 완전종료된 후 새로운 subscriber가 생긴다고 다시 subject가 작동하진 않습니다.
또 subject가 종료되었을 때에 Subscriber에게 종료 이벤트를 줄 뿐만 아니라, 이 후에 구독한 subscriber에게도 종료이벤트를 알려 줍니다!

let subject = PublishSubject<Int>()

let subjectOne = subject
    .subscribe(onNext: { (num) in
        print("subjectOne :",num)
    }, onError: { (error) in
        print("subjectOne Erorr: ",error)
    }, onCompleted: {
        print("subjectOne onCompleted")
    })

subject.onNext(1)
subject.onNext(2)

subject.onCompleted() // 추가

let subjectTwo = subject
    .subscribe(onNext: { (num) in
        print("subjectTwo :",num)
    }, onError: { (error) in
        print("subjectTwo Erorr: ",error)
    }, onCompleted: {
        print("subjectTwo onCompleted")
    })

subject.onNext(3)
subject.onNext(4)
subject.onNext(5)


/*
 subjectOne : 1
 subjectOne : 2
 subjectOne onCompleted
 subjectTwo onCompleted
 */

 

 

BehaviorSubject

BehaviorSubject는 PublicshSubject와 유사하지만, 초기값을 가집니다.
PublishSubject와 달리 항상 직전의 값부터 구독합니다!
초기값이 없다면 PublishSubject를 사용하세요!

 

 

위의 마블을 보시면 PublishSubject와 달리 항상 직전의 값부터 구독하시는걸 볼 수 있습니다.

let subject = BehaviorSubject(value: 5)

let subjectOne = subject
    .subscribe(onNext: { (num) in
        print("subjectOne :",num)
    }, onError: { (error) in
        print("subjectOne Erorr: ",error)
    }, onCompleted: {
        print("subjectOne onCompleted")
    })

subject.onNext(6)
subject.onNext(7)
subject.onNext(8)

let subjectTwo = subject
    .subscribe(onNext: { (num) in
        print("subjectTwo :",num)
    }, onError: { (error) in
        print("subjectTwo Erorr: ",error)
    }, onCompleted: {
        print("subjectTwo onCompleted")
    })

subject.onNext(9)
subject.onNext(10)

/*
subjectOne : 5
subjectOne : 6
subjectOne : 7
subjectOne : 8
subjectTwo : 8
subjectOne : 9
subjectTwo : 9
subjectOne : 10
subjectTwo : 10
 */

 

 

ReplaySubject

ReplaySubject는 생성시 선택한 특정 크기만큼 일시적으로 캐시하거나 버퍼를 저장해서 최신 요소를 모두 방출합니다.
최근 검색어 같은 곳에 사용하면 좋을꺼같아요.

let subject = ReplaySubject<Int>.create(bufferSize: 3)

subject.onNext(1)
subject.onNext(2)
subject.onNext(3)
subject.onNext(4)
subject.onNext(5)
subject.onNext(6)

let subjectOne = subject.subscribe(onNext: { (num) in
    print(num)
})

subject.onNext(7)
subject.onNext(8)
subject.onNext(9)

/*
4
5
6
7
8
9
 */

 

 


 

Relay란

Relay Class는 RxCocoa4에서 구현되었고, PublishRelay BehaviorRelay클래스가 존재합니다.
RxSwift인 Subject와는 다르게 Relay는 RxCocoa의 클래스 입니다.

 

PublishRelay

PublishRelay는 PublishSubject의 Wrapper 클래스입니다.
PublishSubject의 특성처럼 구독 이후의 발생하는 이벤트들만 알 수 있습니다.

public final class PublishRelay<Element>: ObservableType {
  private let _subject: PublishSubject<Element>
  public init() {
      _subject = PublishSubject()
  }
}

 

BehaviorRelay

BehaviorRelay는 BehaviorSubject의 Wrapper 클래스 입니다.
.value를 통해서 현재의 값을 가져올 수 있습니다.
variable이 Deprecate되면서 소개시켜드리지 않았지만 대신에 BehaviorRelay를 사용하시면 됩니다.

public final class BehaviorRelay<Element>: ObservableType {
  private let _subject: BehaviorSubject<Element>

  public var value: Element {
      return try! _subject.value()
  }

  public init(value: Element) {
      _subject = BehaviorSubject(value: value)
  }
}

 

~Subject와 ~Relay의 차이점

~Subject는 .completed, .error의 이벤트가 발생하면 subscribe가 종료되는 반면,
~Relay는 .completed, .error를 발생하지 않고 Dispose되기 전까지 계속 작동하기 때문에 UI Event에서 사용하기 적절합니다.

반응형

'RxSwift' 카테고리의 다른 글

[RxSwift] filter vs skip operator  (0) 2019.09.14
[RxSwift] Observable이란 - (2)  (0) 2019.07.25
[RxSwift] RxSwift의 기본 개념 - (1)  (0) 2019.07.25