apple/RxSwift, ReactorKit

[week3] Subjects

lgvv 2021. 7. 10. 02:18

✅ 이번 시간에는 Subjects에 대해서 알아보도록 하자.

여기 부분이 진짜 엄청 이해가 안간다 ㅠ_ㅠ

 

여기부터는 따로 스타터파일이 제공되지 않아서 내가 직접 코드를 만들어 실습할 예정!

 

이 포스팅에서 커리큘럼 대한 정보

https://github.com/lgvv/RxSwiftStudy/blob/main/week3.md

 

lgvv/RxSwiftStudy

RxSwift를 공부하는 Repository입니다.🐍. Contribute to lgvv/RxSwiftStudy development by creating an account on GitHub.

github.com

✅ 실습 코드에 대한 정보 -> 여기가서 코드를 다운받기!

https://github.com/lgvv/MyRxSwift

 

lgvv/MyRxSwift

나의 RxSwift 공부 기록장. Contribute to lgvv/MyRxSwift development by creating an account on GitHub.

github.com

 

(목차)

1. Subjects란 무엇일까?

2. Subjects 종류 4가지 + Variable

 

 

✅ 들어가기에 앞서...

공식문서에 따르면

 

"ReactiveX에서 observer는 observable 을 구독한다. observer는 observable이 방출하는 모든 아이템(들)에 대해 반응한다"

 

라고 정의되어 있다.

 

✅ 1. Subjects란 무엇일까?

Rx 에서 Subject는 Observable 과 Observer 둘 다 될 수 있는 특별한 형태입니다. Subject는 Observables을 subscribe(구독) 할 수 있고 다시 emit(방출)할 수 도 있습니다. 혹은 새로운 Observable을 emit 할 수 있습니다.

그렇다면 Observable과 Subject의 차이는?

Subscribe 방식의 차이

 

✅ 2. Subjects 종류 3가지 + Variable

1️⃣ Publish Subject 

 - 아무것도 없는 빈 상태로 subscribe를 시작하고, 오직 새로운 elements 만 subscriber에게 emit 시킨다.

Publish Subject

그림에 보다시피 subscribe 이전의 데이터는 받을 수 없어.

        var publishSubject = PublishSubject<String>() // 선언부 
        print(" ==== publish Subject ==== ")
        publishSubject.onNext("publish -> idx 0")
        
        // first subscribe
        publishSubject.subscribe{ event in
            print(event)
        }.disposed(by: disposeBag)
        
        publishSubject.onNext("publish -> idx 1")
        publishSubject.onNext("publish -> idx 2")
        publishSubject.onCompleted() // 만약 이 부분이 빠지면 결과값은 어떻게 될까?
        publishSubject.onNext("publish -> idx 3")
        
        // second subscribe
        publishSubject.subscribe{ event in
            print(event)
        }.disposed(by: disposeBag)
        publishSubject.onNext("publish -> idx 4")
        publishSubject.onCompleted()
        
// 출력값
next(publush -> idx 1)
next(publush -> idx 2)
completed
completed

// 출력값 - 포스팅의 line 12이 없어진다면
next(publish -> idx 1) // first subscribe의 결과
next(publish -> idx 2) // first subscribe의 결과
next(publish -> idx 3) // first subscribe의 결과
next(publish -> idx 4) // first subscribe의 결과
next(publish -> idx 4) // second subscribe의 결과
completed
completed

⭐️⭐️❗️ 여기서 아주 중요한 점이 발생해.

우리가 subscribe를 하면 예상한 결과로는 idx1, 2, 4가 출력되어야 할탠데, 결과는 1과 2만 나왔어. 이게 무슨일일까?

subscribe가 stop event(complete or error)을 받는다면, future subscribers에도 영향을 미쳐서 값 자체가 만들어지지 않아.

first subscribe가 stop event를 받게 되면 이것에 대한 영향이 second subscribe까지 작용한다는 말이야.

그렇다면 위에 있는 주석처럼 만약 complete 부분이 빠지면 다른 결과를 보이는 것을 알 수 있다.

 

 

2️⃣ Behavior Subject
 - 초기화 값을 가진 상태로 시작하는 것이 Publish Subject와의 차이점. 초기값을 방출하거나, 가장 최신의 (가장 늦은) element들을 새 subscribers에게 방출한다.

 

Behavior Subject

얘는 사실상 public Subject와 거의 비슷하지만, behavior의 경우에는 처음에 초기화를 해주는 부분이 필요로 하다. 그리고 가장 최근의 값을 처음 subscribe시에 함께 보내준다.

        var behaviorSubject = BehaviorSubject(value: "hehavior -> init") // 선언부
        print(" ==== behavior Subject ==== ")
        
        behaviorSubject.onNext("behavior -> idx 0")
        // first subscribe
        behaviorSubject.subscribe{ event in
            print(event)
        }.disposed(by: disposeBag)
        behaviorSubject.onNext("behavior -> idx 1")
        behaviorSubject.onNext("behavior -> idx 2")
        //behaviorSubject.onCompleted() // 만약 이 부분이 빠지면 결과값은 어떻게 될까?
        behaviorSubject.onNext("behavior -> idx 3")
        
        // second subscribe
        behaviorSubject.subscribe{ event in
            print(event)
        }.disposed(by: disposeBag)
        behaviorSubject.onNext("behavior -> idx 4")
        behaviorSubject.onCompleted()
        
// 결과값
next(behavior -> idx 0)
next(behavior -> idx 1)
next(behavior -> idx 2)
completed
completed

// 결과값 - 포스팅의 라인 11 사라졌을 때의 결과값
next(behavior -> idx 0) // first subscribe - prev
next(behavior -> idx 1) // first subscribe
next(behavior -> idx 2) // first subscribe
next(behavior -> idx 3) // first subscribe
next(behavior -> idx 3) // second subscribe - prev
next(behavior -> idx 4) // first subscribe
next(behavior -> idx 4) // second subscribe
completed
completed

여기도 마찬가지고, public과 비슷하게 future subscribe에 영향을 미치는 것을 확인할 수 있다. 또한 subscribe전에 갖고 있던 값을 먼저 보여주는 작업 이후에 onNext의 값을 보여준다. 이전 값에 대한 정보로 인해 나타나는 결과값에는 prev를 달았다.

 

 

3️⃣ Replay Subject
 - 초기화 된 buffer size로 시작한다. 그 사이즈까지 buffer의 원소들을 유지하며 새로운 subscriber들에게 방출한다.

Replay Subject

여기의 경우에는 이전에 갖고 있던 값을 모두 보여준다. 다만, 아전의 값들은 버퍼로 지정해준 갯수만큼만 최신 정보를 우선적으로 하여 보여준다. 얘도 코드로 함께 봐보도록 하자.

        var replaySubject = ReplaySubject<String>.create(bufferSize: 2)  
        print(" ==== replay Subject ==== ")
        replaySubject.onNext("replay -> idx 0")
        // first subscribe
        replaySubject.subscribe{ event in
            print(event)
        }.disposed(by: disposeBag)
        replaySubject.onNext("replay -> idx 1")
        replaySubject.onNext("replay -> idx 2")
        replaySubject.onCompleted() // 만약 이 부분이 빠지면 결과값은 어떻게 될까?
        replaySubject.onNext("replay -> idx 3")
        
        // second subscribe
        replaySubject.subscribe{ event in
            print(event)
        }.disposed(by: disposeBag)
        replaySubject.onNext("replay -> idx 4")
        replaySubject.onCompleted()
        
        
// 결과값
next(replay -> idx 0) // first subscribe - buffer
next(replay -> idx 1) // first subscribe 
next(replay -> idx 2) // first subscribe
completed
next(replay -> idx 1) // second subscribe - buffer
next(replay -> idx 2) // second subscribe - buffer
completed

// 결과값 - 이 포스팅에서 라인 10이 사라진다면?
next(replay -> idx 0) // first subscribe - buffer
next(replay -> idx 1) // first subscribe
next(replay -> idx 2) // first subscribe
next(replay -> idx 3) // first subscribe
next(replay -> idx 2) // second subscribe - buffer
next(replay -> idx 3) // second subscribe - buffer
next(replay -> idx 4) // first subscribe
next(replay -> idx 4) // second subscribe 
completed
completed

자 코드를 보자 확실하게 차이가 나는 것이 보인다.

이번에도 공통적으로 확인할 수 있는 것이 중간에 stop event가 있으면 subscribe를 해도 onNext로 데이터를 받아올 수 없다는 것이다.

또한 버퍼에는 가장 최신의 정보가 FIFO(First In First Out)의 형태로 담긴다.

 

4️⃣ async Subject 

 - 오직 마지막 값만 방출 시킨다.

async Subject 

그림에서 보다시피 무조건 마지막 밸류만 방출하는 것을 확인할 수 있다. 또한, 이것도 마찬가지로 stop event가 future subscribe에 영향을 미친다.

        var asyncSubject = AsyncSubject<String>()
        print(" ==== async Subject ==== ")
        asyncSubject.onNext("async -> idx 0")
        
        // first subscribe
        asyncSubject.subscribe{ event in
            print(event)
        }.disposed(by: disposeBag)
        
        asyncSubject.onNext("async -> idx 1")
        asyncSubject.onNext("async -> idx 2")
        asyncSubject.onCompleted() // 만약 이 부분이 빠지면 결과값은 어떻게 될까?
        asyncSubject.onNext("async -> idx 3")
        
        // second subscribe
        asyncSubject.subscribe{ event in
            print(event)
        }.disposed(by: disposeBag)
        asyncSubject.onNext("async -> idx 4")
        asyncSubject.onCompleted()
        
// 결과값
next(async -> idx 2)
completed
next(async -> idx 2)
completed

// 결과값 - 포스팅 코드의 라인 12가 빠졌을 경우
next(async -> idx 4) // first subscribe
next(async -> idx 4) // second subscribe
completed
completed

이것도 코드를 보면 쉽게 이해가 가지? 

 

 

5️⃣ Variable
 - Variable은 Behavior Subject를 래핑하고, 현재의 값을 상태로 저장한다 . 그리고 초기값 또는 가장 최신의 값만 새로운 subscribers에게 방출시킨다. 

❗️이건 공식문서의 Subject쪽에 명시되어 있지 않은데, 커리큘럼에 포함되어 있어서 찾아보았더니..

 

[DEPRECATED] `Variable` is planned for future deprecation. Please consider `BehaviorRelay` as a replacement. Read more at:

 

https://github.com/ReactiveX/RxSwift/issues/1501

 

Moving *Relay into their own Framework. · Issue #1501 · ReactiveX/RxSwift

No deprecation warning in Xcode on using Variable: As per release notes provided here, Variable is deprecated in the favor of BehaviorRelay. But I dont see any deprecation warning on using Variable...

github.com

아무튼 더이상 사용되지 않는다고 하니까 패스!

 

 

 

 

 

 

 

(참고)

https://trilliwon.medium.com/rxswift-%EA%B8%B0%EB%B3%B8-%EC%9D%B5%ED%9E%88%EA%B8%B0-1-d4d77ce63ca8

 

RxSwift 기본 익히기 (1) — 10 분짜리 (updated)

Rx는 충분히 공부하고 사용할 만한 가치가 있는 기술이라고 생각합니다.

trilliwon.medium.com

 

'apple > RxSwift, ReactorKit' 카테고리의 다른 글

[week5] 🌟Transforming Observables  (0) 2021.07.10
[week4] Filtering Observables  (0) 2021.07.10
🐉 RxSwift(Operators) Creating Observables  (0) 2021.07.09
[week2] 👀 Observserbles  (0) 2021.07.08
[week1] Hello RxSwift 🖐  (0) 2021.07.07