๐ŸŽ/RxSwift

[RxSwift] #7) Driver๋ž€ ๋ฌด์—‡์ธ๊ฐ€?? [Driver์™€ Relay]

ir.__.si 2023. 2. 6. 03:32
728x90
๋ฐ˜์‘ํ˜•

๋ณธ ํฌ์ŠคํŒ…์€ ๊ณฐํŠ€๊น€๋‹˜์˜ ๊ฐ•์˜์˜์ƒ์„ ๊ธฐ๋ฐ˜์œผ๋กœ, ๊ฐœ์ธ์ ์œผ๋กœ ๊ณต๋ถ€ํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.

๋”์šฑ ์ž์„ธํ•œ ๋‚ด์šฉ์€, ๊ฐ•์˜ ์˜์ƒ์„ ์ง์ ‘ ์‹œ์ฒญํ•˜์‹œ๋Š”๊ฒƒ์„ ์ถ”์ฒœ๋“œ๋ฆฝ๋‹ˆ๋‹ค! 

 

 

 

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ๊ฐ„๋‹จํ•˜๊ฒŒ Driver๊ฐ€ ๋ฌด์—‡์ธ์ง€์— ๋Œ€ํ•ด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌ ํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!

๊ธ€ ๋งˆ๋ฌด๋ฆฌ์—, 5์ค„์š”์•ฝ์œผ๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌ ํ•œ ๋‚ด์šฉ๋„ ์žˆ์œผ๋‹ˆ ์‹œ๊ฐ„์ด ์—†์œผ์‹  ๋ถ„๋“ค์€ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”.

 

 


 

 

์ด์ „ ํฌ์ŠคํŒ…์—์„œ RxCocoa๋ฅผ ์„ค๋ช… ํ•  ๋•Œ 'UIKit์— Rx์š”์†Œ๋“ค์„ ์ ์šฉ์‹œํ‚จ Extentsion'์ด๋ผ๊ณ  ์„ค๋ช… ํ–ˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค๋ฉด, ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ RxCocoa๋ฅผ ํ™œ์šฉํ•˜์—ฌ UIKit์— ์ง์ ‘์ ์œผ๋กœ Observable์„ ๋ฐ”์ธ๋”ฉ ํ•œ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

viewModel.itemsCount
            .map{"\($0)"}
            .observeOn(MainScheduler.instance)
            .bind(to: itemCountLabel.rx.text)
            .disposed(by: disposeBag)

 

๊ทธ๋Ÿฐ๋ฐ ์ด๋Ÿฌํ•œ 1) UI์— ์ง์ ‘ ๋ฐ”์ธ๋”ฉํ•˜๋Š” ์ž‘์—…์˜ ๊ฒฝ์šฐ์—๋Š” ๋ฐ˜๋“œ์‹œ Main-Thread(UI Thread)์—์„œ ๋™์ž‘์„ ํ•ด์•ผํ•œ๋‹ค๋Š” ํŠน์ง•์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์—, .bind()๋ฅผ ํ•˜๊ธฐ ์ „์— .observeOn(MainScheduler.instance)๋ฅผ ํ†ตํ•ด์„œ

๊ฐ•์ œ๋กœ ํ•ด๋‹น stream์ด Main-Thread์—์„œ ์ง„ํ–‰๋˜๋„๋ก ํ•ด ์ฃผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

๋”ฐ๋ผ์„œ, .bind()๋ฅผ ์‚ฌ์šฉํ•  ๋• ํ•ญ์ƒ .observeOn(MainScheduler.instance)๋ฅผ ๊ฐ™์ด ์ž‘์„ฑ ํ•ด ์ค˜์•ผํ•œ๋‹ค๋Š” ๊ท€์ฐฎ์€ ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋˜ํ•œ UI๋™์ž‘์˜ ๊ฒฝ์šฐ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋˜ ๋„์ค‘ Error๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๊ทธ ์ˆœ๊ฐ„ Stream์ด ๋Š์–ด์ ธ ๋ฒ„๋ฆฌ๊ณ ,

ํ•ด๋‹น Stream์€ ํ•œ๋ฒˆ ์ข…๋ฃŒ๋˜๋ฉด ๋”์ด์ƒ ์žฌ์‚ฌ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

 

์ด๊ฒƒ์€ ์šฐ๋ฆฌ๊ฐ€ UI๋™์ž‘์„ ํ•˜๋‹ค๊ฐ€ Error๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ด UI๋Š” ๋”์ด์ƒ ๋™์ž‘ํ•˜์ง€ ๋ชปํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋Š”๋ฐ,

์ด๋ ‡๊ฒŒ 2) UI๊ฐ€ Error๋ฅผ ๋งˆ์ฃผํ–ˆ์„ ๋•Œ, Stream์ด ๊ทธ๋Œ€๋กœ ์ข…๋ฃŒ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ

.catchErrorJustReturn()์ด๋ผ๋Š” operator๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

 

viewModel.itemsCount
            .map{"\($0)"}
            .catchErrorJustReturn("")
            .observeOn(MainScheduler.instance)
            .bind(to: itemCountLabel.rx.text)
            .disposed(by: disposeBag)

์œ„ ์ฝ”๋“œ์˜ .catchErrorJustReturn("")์„ ํ†ตํ•ด์„œ, Error๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๊ทธ๋Œ€๋กœ ๋นˆ ๋ฌธ์ž์—ด์„ text๋กœ ์ „๋‹ฌํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

์ž ๊ทธ๋ ‡๋‹ค๋ฉด, Rx๋ฅผ UI์— ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์šฐ๋ฆฌ๋Š” 2๊ฐ€์ง€์˜ Operator๊ฐ€ ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1) .catchErrorJustReturn()

2) .observeOn(MainScheduler.instance)

 

ํ•˜์ง€๋งŒ, RxSwift๋Š” ์ด๋Ÿฌํ•œ 2๊ฐ€์ง€์˜ operator๊ฐ€ ํ•˜๋Š” ๊ธฐ๋Šฅ๋“ค์„ 1๊ฐœ์˜ operator๋กœ ์ œ๊ณต ํ•ด ์ฃผ๋Š”๋ฐ

๊ทธ๊ฒƒ์ด ๋ฐ”๋กœ .asDriver()์ž…๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ด .asDriver()๋Š” .bind() ๋Œ€์‹ , .drive()๋ผ๋Š” Operator์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์œ„์—์„œ ๋ณด์—ฌ๋“œ๋ฆฐ ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.

viewModel.itemsCount
            .map{"\($0)"}
            .asDriver(onErrorJustReturn: "")
            .drive(itemCountLabel.rx.text)
            .disposed(by: disposeBag)

์œ„์˜ ์ฝ”๋“œ๋ฅผ ํ•ด์„ํ•ด๋ณด๋ฉด,

 

[Driver๋กœ์จ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋Š”๋ฐ, ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋นˆ ๋ฌธ์ž์—ด("")์„ ๋“œ๋ผ์ด๋ธŒ(๋ฐ”์ธ๋”ฉ)ํ•˜๊ณ  ์•„๋‹ˆ๋ผ๋ฉด ๊ฐ’์„ ๋“œ๋ผ์ด๋ธŒ(๋ฐ”์ธ๋”ฉ) ํ• ๊ฒŒ!]

 

๋ผ๊ณ  ํ•ด์„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ฆ‰, Driver๋Š” Observable์˜ ๊ธฐ๋Šฅ์€ ํ•˜์ง€๋งŒ UI๋™์ž‘์— ํŠนํ™”๋œ Observable์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์‹œ๋ฉด๋ฉ๋‹ˆ๋‹ค!

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์—, ์•„๋ž˜์™€ ๊ฐ™์ด ์„ ์–ธ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค!

 var ์ผ๋ฐ˜์ ์ธ_Observable : Observable<[Menu]>
 var UI์—_ํŠนํ™”๋œ_Observavle : Driver<[Menu]>

 

 

 

์ž ๊ทธ๋ ‡๋‹ค๋ฉด, ๋ญ”๊ฐ€ Observable๋ฟ ์•„๋‹ˆ๋ผ, Subject๋˜ํ•œ ์ด๋Ÿฌํ•œ ๋™์ผํ•œ ์ด์œ ๋กœ UI์ž‘์—…์„ ์œ„ํ•œ ํŠน๋ณ„ํ•œ ๋ฌด์–ธ๊ฐ€๊ฐ€ ์žˆ์ง€ ์•Š์„๊นŒ์š”??

 

๋ฐ”๋กœ ๊ทธ๊ฒƒ์„ Relay๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค!

๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ๊ฐ€ ๊ธฐ์กด์— ์‚ฌ์šฉํ–ˆ๋˜ BehaviorSubject๋ฅผ BehaviorRelay๋กœ ๋ฐ”๊ฟ”์ฃผ๋ฉด

Error์ฒ˜๋ฆฌ๋‚˜, Completed๋˜๋Š” ์ƒํ™ฉ์— ๋Œ€ํ•œ ์‹ ๊ฒฝ์„ ์“ฐ์ง€ ์•Š์•„๋„ ๋˜๊ธฐ ๋•Œ๋ฌธ์—

.onNext() Operator๊ฐ€ .accept() Operator๋กœ ๋Œ€์ฒด๋˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค!

 

class MenuListViewModel{
    
    var menusObservable = BehaviorSubject<[Menu]>(value: [])
    
    func clearAllItemSelections(){
        menusObservable
            .map {
                $0.map{ m in
                    Menu(id: m.id, name: m.name, price: m.price, count: 0)
                }
            }
            .take(1)
            .subscribe (onNext:{
                self.menusObservable.accept($0)
                // self.menusObservable.onNext($0)
                // ํ•ด๋‹น ๋ถ€๋ถ„์—์„œ .onNext($0) -> .accept($0)๋กœ ๋ณ€๊ฒฝ ๋จ
            })
    }
}

 

 

 

<5์ค„ ์š”์•ฝ>

1. UI๋™์ž‘์€ Main Thread(UI Thread)์—์„œ๋งŒ ๋Œ์•„๊ฐ€๊ณ , Error๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด Stream์ด ๋ฐ”๋กœ ๋Š์–ด์ง€๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ด์•ผ ํ•จ.

2. ์ด๋ฅผ ์œ„ํ•ด, Operator๋กœ .asDriver()๋ฅผ ์ œ๊ณตํ•˜๊ณ  .bind()๋Œ€์‹  .drive()์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•จ.

3. ์ฆ‰, Driver๋Š” UI์ž‘์—…์— ํŠนํ™”๋œ Observable์˜ ์ข…๋ฅ˜์ž„.

4. Driver์™€ ๋™์ผํ•œ ์ด์œ ๋กœ Subject์—์„œ ํŒŒ์ƒ๋œ ๊ฒƒ์ด Relay์ž„.

5. ์ด๋Ÿฌํ•œ Relay๋Š” .onNext() ๋Œ€์‹  .accept()๋ฅผ ์‚ฌ์šฉํ•จ. ์™œ๋ƒํ•˜๋ฉด Error๋‚˜ Completed๋ฅผ ๊ณ ๋ คํ•˜์ง€ ์•Š์•„๋„ ๋˜๊ธฐ ๋•Œ๋ฌธ์ž„.

 

+

Subject<T>๋กœ ๋ฐฉ์ถœํ•œ ๊ฐ’์ด, ํŠน์ • stream์—์„œ UI์ž‘์—…์œผ๋กœ ์ง„ํ–‰๋œ๋‹ค๋ฉด .asDriver()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ 

ํ•ด๋‹น ๊ตฌ๊ฐ„์—์„œ๋งŒ Observable์„ Driver๋กœ ๋ฐ”๊ฟ”์ค€๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

ํ•˜์ง€๋งŒ, ์ค‘๊ฐ„์— ๋ฐ์ดํ„ฐ ๊ฐ’์˜ ๋ณ€ํ™˜ ์—†์ด ์ฒ˜์Œ๋ถ€ํ„ฐ UI์— ์—ฐ๊ฒฐ ํ•  ๋ชฉ์ ์ด๋ฉด Driver<T>๋กœ Observable์„ ์ƒ์„ฑํ•ด๋„ ๋œ๋‹ค.

(๊ทธ๋Ÿฐ๋ฐ ์—ฌ๋Ÿฌ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด ๋ณธ ๊ฒฐ๊ณผ, ์ผ๋‹จ ๊ฐ€์žฅ ๋งŒ๋งŒํ•œ(?) Subject๋กœ ์ƒ์„ฑํ•ด๋†“๊ณ , ํ•„์š”ํ•œ Stream์—์„œ .asDriver()๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค....! )

728x90
๋ฐ˜์‘ํ˜•