Focus On Develop ๐ŸคŸ๐ŸคŸ

[RxSwift] Subject ๋ณธ๋ฌธ

iOS [Swift]/๊ธฐ์ดˆ๋ฅผ ํƒ„ํƒ„ํžˆ!

[RxSwift] Subject

๋ˆ„๋ฆฌ๋‹ฌ์ดํ‹€ 2021. 3. 30. 23:16

์ด์ „ ํฌ์ŠคํŒ…์—์„œ RxSwift ์— ๋Œ€ํ•œ ๊ธฐ๋ณธ์ ์ธ ๊ฐœ๋…๊ณผ ์‚ฌ์šฉ๋ฒ•์„ ์•Œ์•„๋ดค๋Š”๋ฐ์š”~!!

๊ทผ๋ฐ ํ•œ๊ฐ€์ง€ ์˜๋ฌธ์ ์ด ์ƒ๊ธฐ์ฃ !

 

Observable์„ ๊ตฌ๋…ํ•˜๋ฉด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ๋ฐ›๊ธฐ๋Š” ํ•˜๋Š”๋ฐ, ๋ฐ˜๋Œ€๋กœ Observable์— ๋ฐ์ดํ„ฐ ๋ณ€ํ™”๋Š” ์–ด๋–ป๊ฒŒ ์ค„ ์ˆ˜ ์žˆ์„๊นŒ์š”?

๊ทธ๋ž˜์•ผ ๋ณ€๊ฒฝ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ๊ตฌ๋…ํ•ด์„œ User Interaction์— ๋”ฐ๋ผ ๋ญ”๊ฐ€ UI์— ๋ณ€ํ™”๋ฅผ ์ค„ํ…๋ฐ์š”!

 

์—ฌ๊ธฐ์„œ ๋‚˜์˜จ๊ฒŒ ๋ฐ”๋กœ Subject ์ž…๋‹ˆ๋‹ค. ํ•œ๋ฒˆ Subject์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ๊นŒ์š”~~~ ๐Ÿ‘‰

 


reactivex.io/documentation/subject.html

 

ReactiveX - Subject

If you have a Subject and you want to pass it along to some other agent without exposing its Subscriber interface, you can mask it by calling its asObservable method, which will return the Subject as a pure Observable. See Also

reactivex.io

๊ณต์‹ ๋ฌธ์„œ์— Subject์— ๋Œ€ํ•ด ์ž˜ ๋‚˜์™€์žˆ๋Š”๋ฐ, ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ•ด๋ณผ๊ฒŒ์š”!!

 

Subject๋Š” Observable์ฒ˜๋Ÿผ ๊ฐ’์„ ๋ฐฐ์ถœํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ๊ตฌ๋…๋„ ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ฆ‰ Observable์ด๋ฉด์„œ Observer์ด๊ธฐ๋„ ํ•œ๊ฑฐ์ฃ .

Subject๋Š” ๋™์ ์œผ๋กœ ๊ฐ’์„ Control ๋ฐ ๋ฐฐ์ถœํ•  ์ˆ˜ ์žˆ๊ณ , ๊ตฌ๋…ํ•˜๊ณ  ์žˆ๋Š” "Observer๋“ค"์—๊ฒŒ ๊ฐ’์„ ๋ฐฐ์ถœํ•ฉ๋‹ˆ๋‹ค. (muticast ๋ฐฉ์‹)

Observable๊ณผ ์ฐจ์ด์ ์€ ๊ตฌ๋…์ค‘์ธ ํ•˜๋‚˜์˜ Observer์—๊ฒŒ๋งŒ ๊ฐ’์„ ๋ฐฐ์ถœํ•œ๋‹ค๋Š” ์ฐจ์ด์ ์ด ์žˆ์–ด์š”. (unicast ๋ฐฉ์‹)

 

 

Subject๋Š” 4๊ฐ€์ง€ ์ข…๋ฅ˜๊ฐ€ ์žˆ์–ด์š”.

 

 

PublishSubject

๊ฐ€์žฅ ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” Subject์—์š”.

Subject์— ๋ฐ์ดํ„ฐ๊ฐ€ ์ƒ์„ฑ๋˜๋ฉด ํ•ด๋‹น Subject๋ฅผ ๊ตฌ๋…ํ•˜๋Š” Observer๋“ค์—๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐฐ์ถœํ•ด์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

 

** ์˜ˆ์‹œ

let publishSubject = PublishSubject<Int>()
        publishSubject
            .debug()
            .subscribe { print("first subscribe: \($0)") }
            .disposed(by: disposeBag)
        
        publishSubject.onNext(1)
        publishSubject.onNext(2)
        
        publishSubject
            .debug()
            .subscribe { print("second subscribe: \($0)") }
            .disposed(by: disposeBag)
        
        publishSubject.onNext(3)
        publishSubject.onNext(4)
        publishSubject.onCompleted()

ํ•˜๋‚˜์˜ subject๊ฐ€ ๊ตฌ๋…ํ• ๋•Œ 1,2 ์ด๋ฒคํŠธ๋ฅผ ๋ฐฐ์ถœํ•˜๊ณ , ๋‘๋ฒˆ์งธ subject๊ฐ€ ๊ตฌ๋…์„ ์‹œ์ž‘ํ–ˆ์–ด์š”.

๋‘๋ฒˆ์งธ subject๋Š” ๊ตฌ๋… ์‹œ์  ์ดํ›„์— ๋ฐœ์ƒํ•œ ์ด๋ฒคํŠธ์ธ 3,4๋งŒ ์ˆ˜์‹ ํ•œ ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์–ด์š”.

 

 

BehaviorSubject

๊ธฐ๋ณธ๊ฐ’์„ ํ•˜๋‚˜ ๊ฐ€์ง€๊ณ  ์‹œ์ž‘ํ•ด์š”. ์–ด๋–ค Observer๊ฐ€ ๊ตฌ๋… ํ•˜์ž๋งˆ์ž ๊ธฐ๋ณธ๊ฐ’์„ ๋ฐ”๋กœ ๋ฐฐ์ถœํ•ด์ค˜์š”.

๋งŒ์•ฝ ์ค‘๊ฐ„์— ์ƒˆ๋กœ์šด Observer๊ฐ€ ๊ตฌ๋…ํ•˜๊ฒŒ ๋˜๋ฉด, ๊ฐ€์ง€๊ณ  ์žˆ๋˜ ์ตœ์‹  ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ”๋กœ ๋ฐฐ์ถœํ•ด์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•ด์š”.

 

** ์˜ˆ์‹œ

let behaviorSubject = BehaviorSubject<Int>(value: 100)
        behaviorSubject
            .debug()
            .subscribe { print("first subscribe: \($0)") }
            .disposed(by: disposeBag)
        
        behaviorSubject.onNext(1)
        behaviorSubject.onNext(2)
        
        behaviorSubject
            .debug()
            .subscribe { print("second subscribe: \($0)") }
            .disposed(by: disposeBag)
        
        behaviorSubject.onNext(3)
        behaviorSubject.onNext(4)
        behaviorSubject.onCompleted()

์˜ˆ์ƒ๋Œ€๋กœ๋„ค์š”!!

์ดˆ๊ธฐ๊ฐ’ 100์„ ๊ฐ€์ง€๊ณ  ์‹œ์ž‘ํ–ˆ๊ณ , ์ฒซ๋ฒˆ์งธ subject๊ฐ€ ๊ตฌ๋…ํ•˜์ž๋งˆ์ž 100 ์ด๋ฒคํŠธ๋ฅผ ๋ฐฐ์ถœํ•ด์คฌ์Šต๋‹ˆ๋‹ค.

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋‘๋ฒˆ์งธ subject๊ฐ€ ๊ตฌ๋…์„ ํ•˜์ž๋งˆ์ž ๊ฐ€์ง€๊ณ  ์žˆ๋˜ ์ตœ์‹  ๋ฐ์ดํ„ฐ์ธ 2๋ฅผ ๋ฐ”๋กœ ๋ฐฐ์ถœํ•ด์คฌ์–ด์š”!!

 

 

 

AsyncSubject

์—ฌ๋Ÿฌ Observer๊ฐ€ ๊ตฌ๋…ํ•˜๊ณ  ์žˆ๋Š” ๋„์ค‘์—๋„, ์ค‘๊ฐ„์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๊ณ  ๋ฐ”๋กœ ๋ฐฐ์ถœํ•ด์ฃผ์ง€ ์•Š์•„์š”.

๋Œ€์‹ , ๋งˆ์ง€๋ง‰์— Completed ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„๋•Œ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— ๋ฐœ์ƒํ•œ ๋ฐ์ดํ„ฐ๋งŒ ๋ฐฐ์ถœํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•ด์š”.

 

** ์˜ˆ์‹œ

func testAsyncSubject() {
        let asyncSubject = AsyncSubject<Int>()
        asyncSubject
            .debug()
            .subscribe { print($0) }
            .disposed(by: disposeBag)
        
        asyncSubject.onNext(1)
        asyncSubject.onNext(2)
        asyncSubject.onNext(3)
        asyncSubject.onCompleted()
    }

๊ตฌ๋…ํ•˜๋Š” ๋„์ค‘์— 1,2,3 ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ Next ์ด๋ฒคํŠธ๊ฐ€ 3๋ฒˆ ๋ฐœ์ƒํ–ˆ์ง€๋งŒ, ์‹ค์ œ๋กœ๋Š” ๋งˆ์ง€๋ง‰์— complete ์ด๋ฒคํŠธ๊ฐ€ ํ˜ธ์ถœ๋ ๋•Œ ๋งˆ์ง€๋ง‰์— ์ƒ์„ฑ๋œ 3๋งŒ next์ด๋ฒคํŠธ๋กœ ๋ฐฐ์ถœ๋˜๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์–ด์š”.

 

 

ReplaySubject

๊ธฐ๋ณธ์ ์ธ ๋™์ž‘์€ PublishSubject์™€ ์œ ์‚ฌํ•œ๋ฐ, ์ค‘๊ฐ„์— ๋‹ค๋ฅธ Observer๊ฐ€ ๊ตฌ๋…ํ•˜๊ธฐ ์‹œ์ž‘ํ•˜๋ฉด ์ง€๊ธˆ๊นŒ์ง€ ๋ฐœ์ƒํ–ˆ๋˜ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ Buffer Size(๋ช‡๊ฐœ๋‚˜ ๋ฐฐ์ถœํ•ด์ค„๊ฑด์ง€) ๋ฐฐ์ถœํ•ด์ฃผ๊ณ , ์ดํ›„๋ถ€ํ„ฐ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐœ์ƒํ• ๋•Œ๋งˆ๋‹ค ๋ฐฐ์ถœํ•ด์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

 

** ์˜ˆ์‹œ

let replaySubject = ReplaySubject<Int>.create(bufferSize: 2)
        replaySubject
            .debug()
            .subscribe { print("first subscribe: \($0)") }
            .disposed(by: disposeBag)
        
        replaySubject.onNext(1)
        replaySubject.onNext(2)
        replaySubject.onNext(3)
        
        replaySubject
            .debug()
            .subscribe { print("second subscribe: \($0)") }
            .disposed(by: disposeBag)
        
        replaySubject.onNext(4)
        replaySubject.onCompleted()

๋„ค~!! ์ด๊ฒƒ๋„ ์˜ˆ์ƒ๋Œ€๋กœ ์ž…๋‹ˆ๋‹ค ๐Ÿ‘

์ฒซ๋ฒˆ์งธ subject๊ฐ€ ๊ตฌ๋…์„ ์‹œ์ž‘ํ•˜๊ณ  1,2,3 ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐฐ์ถœํ•ด์คฌ์–ด์š”. ๊ทธ๋•Œ ๋‘๋ฒˆ์งธ subject๊ฐ€ ๊ตฌ๋…์„ ์‹œ์ž‘ํ–ˆ๊ณ , ์ง€๊ธˆ๊นŒ์ง€ ๋ฐœ์ƒํ–ˆ๋˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋‘ ์ˆ˜์‹ ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ์š”! ์—ฌ๊ธฐ์„œ ์ƒ์„ฑ์‹œ์ ์— Buffer ํฌ๊ธฐ๋ฅผ 2๋กœ ๋งŒ๋“ค์–ด ์คฌ์œผ๋‹ˆ, ์‹ค์ œ๋กœ 1~3์˜ 3๊ฐœ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐœ์ƒํ–ˆ์—ˆ์ง€๋งŒ ์ตœ์‹  2๊ฐœ์ธ 2,3์— ๋Œ€ํ•œ ์ด๋ฒคํŠธ๋งŒ ์ˆ˜์‹ ํ•˜๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์–ด์š”!

 


์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” Subject์˜ ๊ฐœ๋…๊ณผ ์ข…๋ฅ˜, ์ข…๋ฅ˜๋ณ„๋กœ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ํ•œ๋ฒˆ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค ๐Ÿ˜Ž

์˜ค๋Š˜๋„ ๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ๋„์›€์ด ๋˜์—ˆ๊ธธ ๋ฐ”๋ž˜์š” ๐Ÿ™

 

 

Comments