Rxswift Basic 3탄

Eddy📱·2022년 7월 15일
0

RxSwift

목록 보기
1/4
post-thumbnail

Rxswift 3탄에서는 Subject에 대해 알아보려고한다!

아직 알아봐야할 것들이 많기에 후다닥 정리한 것을 적으려고 한다

Subject는 문서에 따르면 Observer, Observable 2가지 기능을 하는 것을 말한다.

Observer로서 이것은 하나 이상의 Observables를 subscribe하고 있다.

Observable로서 아이템 하나하나 거치면서 재배출하고 관찰하며 새로운 items들을 배출할 수 있다.

여기에서 Observable에 대해 hot, cold 2가지로 나뉘어져 있다.

이는 공식문서에서 아래와 같이 쓰여져 있다

When does an Observable begin emitting its sequence of items? It depends on the Observable. A “hot” Observable may begin emitting items as soon as it is created, and so any observer who later subscribes to that Observable may start observing the sequence somewhere in the middle. A “cold” Observable, on the other hand, waits until an observer subscribes to it before it begins to emit items, and so such an observer is guaranteed to see the whole sequence from the beginning.

의미를 파악하자면 아래와 같다.

cold Observable는 items들을 방출하기 시작하기 전에 Observable의 구독을 기다린다. 그러므로 구독한 순간부터 방출을 시작한다.

hot Observable는 Observable이 생성되는 즉시 방출하기 시작하고 중간의 아이템을 방출하고 있더라도 그 아이템을 방출하기 시작한다.

그래서 쉽게 말하자면 hot는 구독한 순간부터 시퀀스의 중간 아이템을 방출하더라도 그 순간부터의 이벤트를 전달하는 것 같다.

그래서 이는 Live Streaming를 생각하면된다. 내가 화면을 킨 순간부터 이어서 이벤트를 보여주고 있다.

cold는 구독한 순간에 시퀀스의 처음부터 끝까지의 이벤트를 전달해주 것 같다.

이 예시로는 VOD를 볼 수 있다. 내가 튼 순간이 처음이고 끝까지 볼 수 있다.

이제 Subject에 대해 알아볼 예정이다.

Subject는 4가지가 존재한다.

AsyncSubject

이 Subject는 마지막의 값을 배출한다. 하지만 Observable이 끝나야만 배출해준다. 그래서 만약 끝나지 않는다면 어떤 값들도 배출하지 않는다.

그리고 만약 에러로 종료되면 마지막 이벤트 전달없이 에러가 발생된다.

BehaviorSubject

이 Subejct는 초기값을 가지고 있다. 그래서 구독이 시작하면 초기값을 주고, 그이후에 들어오는 값을 배출한다.

이것도 동일하게 에러로 종료가 된다면 다음의 Observers에게 어떤 아이템도 배출하지 않을 것이다.

let subject = BehaviorSubject(value: "Initial value")

이렇게 초기값을 넣어줄 수 있다.

이는 처음 구독했을떄 제공할 초기값이다!
이 부분외에는 PublishSubject와 다를바가 없기 때문에 PublishSubject에서 자세히 작성한 코드를 참고하면 될 것이다.

PublishSubject

이 Subject는 Behavior와 비슷하지만 초기값을 가지지 않는다. 그러므로 구독 이후에 들어오는 값을 배출해준다.

그리고 주의해야할 점은 PublishSubject가 만들어지자마자 즉시 배출을 시작한다. 그래서 만약 Subject가 만들어지고 observer가 구독하게 되면 이곳에서 즉시 배출하므로 한 두개의 items를 잃을 수도 있다.

왜냐하면 생성하자마자 배출을 하는데, 구독하는 시점과 일부 차이가 존재할 수도 있기 때문에

그래서 이를 보장받기 위해서 Create를 활용해서 cold Observable를 활용해야 한다.

아니면 ReplaySubject를 활용하는 것도 방법이 된다!

이것도 동일하게 에러가 발생하면 다음 Observers에게 items를 배출하지 않을 것이다

예시를 보면 아래와 같다


let subject = PublishSubject<String>()
subject.onNext("Is anyone listening?")

let subscriptionOne = subject
    .subscribe(onNext: { (string) in
        print(string)
    })
subject.on(.next("1"))
subject.onNext("2")

let subscriptionTwo = subject
    .subscribe({ (event) in
        print("2)", event.element ?? event)
    })

subject.onNext("3")
subscriptionOne.dispose()
subject.onNext("4")
subject.onCompleted()
subject.onNext("5")
subscriptionTwo.dispose()

먼저 subscriptionOne에서 구독을 subject를 구독을 시작한다.

그럼 구독한 시점부터 들어오는 아이템들을 받게 되는 것이다!

1를 내보내주고, 2를 내보내고 3를 내보내는 것을 볼 수 있다.

이로써 subscriptionOne에서 1 2 3이 각각 한줄씩 출력되는 것을 볼 수 있다.

그 이후에 dispose가 되기 떄문에 이곳에서는 더이상 구독이 되어있지 않으므로 이벤트를 받지 않는다.

또 이제 subscriptionTwo를 보게되면 구독한 시점부터 값을 받는 것을 볼 수 있다.

그러므로 3 4 completed가 출력이 되는 것을 볼 수 있다.

이렇게 마지막에 dispose를 해서 이 구독이 끝이 났다는 것을 알려주어야 한다!!

dispose관련된 것은 추후에 또 작성할 예정이다!

ReplaySubject

이 Subject는 Observer가 언제 구독하든지 상관없이 Observable로부터 배출되는 모든 아이템들을 모든 Observer에게 배출해준다.

그러나 여기에도 주의해야할 점이 있다.

여기에서는 buffer를 사용하는데 이 buffer의 크기를 넘게 된다면 예전의 items를 없애버린다..! 또는 일정 시간이 지나면 없애기도한다..!

사용에 주의해야할 것같다

그래서 만약 ReplaySubject를 사용하게 되면 onNext를 여러 threads에서 호출하지 말아야한다!

이렇게 연속적이지 않고 다발적으로 사용하게 된다면 Observable이 충돌하게 되고 결과가 원하는 것처럼 나오지 않을 가능성이 존재한다.

그러므로 ReplaySubject를 사용할 때에는 Buffer 관리와 onNext의 사용을 주의해야한다.

코드를 보면 아래와 같다

let subject = ReplaySubject<String>.create(bufferSize: 2)
    let disposeBag = DisposeBag()
    
    subject.onNext("1")
    subject.onNext("2")
    subject.onNext("3")
    
    subject.subscribe { (event) in
        print(event.element ?? event)
        }
        .disposed(by: disposeBag)
    
    subject
        .subscribe { (event) in
            print(event.element ?? event)
        }
        .disposed(by: disposeBag)

버퍼 사이즈 2를 가지는 ReplaySubject를 만든다.

생성은 .create(bufferSize:) 메소드를 이용해서 만들면 된다.

1, 2, 3 세 개의 요소들을 subject에 추가한다.

해당 subject에 대한 두 개의 구독자를 생성한다.

최근 두개의 요소2,3은 각각의 구독자에게 보여진다.

값1은 방출되지 않는다.

왜냐하면 버퍼사이즈가 2이기 떄문에 사이즈를 넘어가기 때문이다!

그래서 2 3 2 3 이렇게 각 한줄마다 하나씩 4개가 출력되는 것을 볼 수 있다.

참고사이트

https://reactivex.io/documentation/subject.html
https://github.com/fimuxd/RxSwift/blob/master/Lectures/03_Subjects/Ch3.%20Subjects.md

profile
Make a better world

0개의 댓글