ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

728x90
๋ฐ˜์‘ํ˜•

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

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

 

 

 

์ด์ „์— ํฌ์ŠคํŒ…ํ•œ [RxSwift] #3) RxSwift๋ฅผ ํ™œ์šฉํ•œ MVVMํŒจํ„ด [1] ์— ์ด์–ด์ง€๋Š” ํฌ์ŠคํŒ… ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ, ์ด๋ฒˆ ๊ธ€๋ถ€ํ„ฐ ์ฝ”๋“œ๋‚ด์šฉ์„ ์บก์ณ ํ˜•์‹์ด ์•„๋‹Œ, ์ฝ”๋“œ๋ธ”๋Ÿญ ํ˜•์‹์œผ๋กœ ์ž‘์„ฑ ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค!


์ด์ „ํฌ์ŠคํŒ…์—์„œ Observable๋กœ ์ƒ์„ฑํ•œ ๋ณ€์ˆ˜๋ฅผ, ๊ตฌ๋… ํ•œ ์ดํ›„์—๋„ ์ง€์†์ ์ธ ๊ฐ’์˜ ๋ณ€๊ฒฝ์„ ๊ด€์ฐฐํ•ด์•ผํ•˜๋Š” ํ•„์š”๊ฐ€ ์ƒ๊ฒจ

์ด๋ฅผ์œ„ํ•ด Observable์„ Subject๋กœ ๊ตฌํ˜„ํ•ด์•ผ ํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

(Subject์— ๋Œ€ํ•œ ์„ค๋ช…์€ ์ด ๊ฒŒ์‹œ๋ฌผ์„ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”!)

class MenuListViewModel{
    var menus : [Menu] = [
        Menu(name: "ํŠ€๊น€1", price: 100, count: 0),
        Menu(name: "ํŠ€๊น€1", price: 100, count: 0),
        Menu(name: "ํŠ€๊น€1", price: 100, count: 0),
        Menu(name: "ํŠ€๊น€1", price: 100, count: 0)
    ]
    
    var itemsCount : Int = 5
    var totalPrice : PublishSubject<Int> = PublishSubject()
}

Observable ๋Œ€์‹  Subject๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด, ๊ฐ€์žฅ ๋ณดํŽธ์ ์œผ๋กœ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” PublishSubject๋ฅผ ์ ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

 

override func viewDidLoad() {
        super.viewDidLoad()
        updateUI()
        
        viewModel.totalPrice
            .map{$0.currencyKR()}
            .subscribe(onNext: {self.totalPrice.text = $0})
            .disposed(by: disposeBag)
    }

@IBAction func onOrder(_ sender: UIButton) {
        // TODO: no selection
        // showAlert("Order Fail", "No Orders")
        // performSegue(withIdentifier: "OrderViewController", sender: nil)
        
        viewModel.totalPrice.onNext(100)
        
    }

๊ทธ๋ฆฌ๊ณ 

1) PublishSubject๋ฅผ ํ†ตํ•ด์„œ 100์ด๋ผ๋Š” ๊ฐ’์„ ๋ฟŒ๋ ค์ฃผ๋ฉด,

2) .subscribe๋ฅผ ํ†ตํ•ด ๊ฐ’์„ Label์— ๋ฟŒ๋ ค์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 

ํ•˜์ง€๋งŒ, ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์€ ์ด 100์ด๋ผ๋Š” ๊ฐ’์ด ์•„๋‹ˆ๋ผ, ORDER๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๊ฐ’์ด ๊ณ„์† ์ฆ๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ์›ํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ .scan() ์ด๋ผ๋Š” Operator๋ฅผ ์‚ฌ์šฉํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

override func viewDidLoad() {
        super.viewDidLoad()
        updateUI()
        
        viewModel.totalPrice
            .scan(0, accumulator:+)
            .map{$0.currencyKR()}
            .subscribe(onNext: {self.totalPrice.text = $0})
            .disposed(by: disposeBag)
    }

.scan์€, seed๊ฐ’์ธ 0์— ๊ฐ’์ด ๋“ค์–ด์˜ฌ ๋•Œ ๋งˆ๋‹ค + ํ•œ ๊ฐ’์„ ๋ฐฉ์ถœํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ฆ‰, 100 -> 200 -> 300 ... ์ด๋Ÿฐ์‹์œผ๋กœ ๊ณ„์† ์ฆ๊ฐ€๋œ ๊ฐ’์„ ๋ฐฉ์ถœํ•ฉ๋‹ˆ๋‹ค.

 

์ฒ˜์Œ updateUI() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์˜€์„ ๋•, ๊ฐ’์ด ๋ฐ”๋€” ๋•Œ ๋งˆ๋‹ค updateUI()๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ, PublishSubject๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด .subscribe() ํ•œ๋ฒˆ์œผ๋กœ ๊ฐ’์ด ๋ฐ”๋€” ๋•Œ ๋งˆ๋‹ค ์ž๋™์œผ๋กœ ๊ฐ’๊ณผ UI๊ฐ€ ๋ฐ”๋€๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๊ธฐ์กด์— ๋งŒ๋“ค์–ด ๋‘”, updateUI()๋ฅผ ์‚ญ์ œ ํ•ด์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

 

 

var menus : [Menu] = [
        Menu(name: "ํŠ€๊น€1", price: 100, count: 0),
        Menu(name: "ํŠ€๊น€1", price: 100, count: 0),
        Menu(name: "ํŠ€๊น€1", price: 100, count: 0),
        Menu(name: "ํŠ€๊น€1", price: 100, count: 0)
    ]

var totalPrice : PublishSubject<Int> = PublishSubject()

๊ทธ๋ฆฌ๊ณ  ์‚ฌ์‹ค ์ด totalPrice๋ผ๋Š” ๊ฐ’์€ menus์˜ ๊ฐ Element๋“ค์ธ Menu์˜ (price * count)์˜ ํ•ฉ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ์ € menus์— ๋Œ€ํ•œ Observable์ด ์žˆ๋‹ค๋ฉด, ๊ฐ Element์— ์ ‘๊ทผํ•ด์„œ price*count์˜ ๊ฐ’์„ ๋นผ์˜ฌ ์ˆ˜ ์žˆ์ง€ ์•Š์„๊นŒ์š”??

 

 

class MenuListViewModel{
    var menus : [Menu] = [
        Menu(name: "ํŠ€๊น€1", price: 100, count: 0),
        Menu(name: "ํŠ€๊น€1", price: 100, count: 0),
        Menu(name: "ํŠ€๊น€1", price: 100, count: 0),
        Menu(name: "ํŠ€๊น€1", price: 100, count: 0)
    ]
    
    lazy var menusObservable = Observable.just(menus)
    
    var itemsCount : Int = 5
    lazy var totalPrice = menusObservable
        .map{$0.map{$0.price * $0.count}.reduce(0,+)}
}

lazy ๋ณ€์ˆ˜๋กœ ๋งŒ๋“ค์–ด์ฃผ๋Š” ์ด์œ ๋Š”, menus์™€ menusObservable์€ ๋ฉค๋ฒ„๋ณ€์ˆ˜๋กœ ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

(lazy ํ‚ค์›Œ๋“œ ๊ด€๋ จ ์ž์„ธํ•œ ์„ค๋ช…์€ ์ด ๊ฒŒ์‹œ๋ฌผ์„ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”!)

 

์œ„ ์ฝ”๋“œ์ฒ˜๋Ÿผ, menus๊ฐ€ ๊ฐ€์ง„ ๊ฐ Menu๋“ค์˜ count*price๋ฅผ ๋ชจ๋‘ ๋”ํ•ด์„œ totalPrice์— ์ „๋‹ฌํ•ด์ค๋‹ˆ๋‹ค.

 

 

ํ•œ๋ฒˆ, ์œ„์˜ ์ฝ”๋“œ์˜ ํ๋ฆ„์„ ๋”ฐ๋ผ๊ฐ€๋ด…์‹œ๋‹ค.

 

1) menus์˜ ์š”์†Œ์ธ Menu๋“ค์˜ count๋‚˜ price๊ฐ€ ๋ณ€ํ•œ๋‹ค.

2) menusObservable์ด Onservable.just()๋ฅผ ํ•ด์คŒ์œผ๋กœ์จ, menus์˜ ์ƒํƒœ๋ฅผ ๊ณ„์† ๊ด€์ฐฐํ•˜๊ณ  ๋ฐ˜์˜ํ•œ๋‹ค.

3) totalPrice๋Š”, menusObservable์ด ๊ณ„์† ๊ด€์ฐฐํ•˜๊ณ  ์žˆ๋Š” ๊ฐ’์„ ์ด์šฉํ•˜์—ฌ ํ•ฉ๊ณ„ ๊ธˆ์•ก์„ ๊ณ„์‚ฐํ•˜๊ณ  ์ €์žฅํ•œ๋‹ค.

 

๊ทธ๋Ÿผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ itemsCount๋„ ํ•œ๋ฒˆ ๋‹ค์‹œ ๋งŒ๋“ค์–ด๋ณผ๊นŒ์š”??

 

    lazy var itemsCount = menusObservable
        .map{$0.map{$0.count}.reduce(0,+)}

์œ„์™€ ๊ฐ™์ด itemsCount๋ฅผ ๋งŒ๋“ค์–ด ์ค€๋‹ค๋ฉด, Menu๋“ค์˜ ๊ฐฏ์ˆ˜๊ฐ€ ๋ฐ”๋€” ๋•Œ ๋งˆ๋‹ค ์ž๋™์œผ๋กœ ์ „์ฒด ๊ฐฏ์ˆ˜๊ฐ€ ๊ณ„์‚ฐ๋˜์–ด ์ €์žฅ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค!

 

 

 

์ž, ๊ทธ๋ ‡๋‹ค๋ฉด ์•„๋ž˜์˜ ์ฝ”๋“œ๋„ ๋ญ”๊ฐ€ ๋ฐ”๋€Œ์–ด์•ผ ํ•  ๊ฒƒ ๊ฐ™์ง€ ์•Š๋‚˜์š”??

lazy var menusObservable = Observable.just(menus)

๋งž์Šต๋‹ˆ๋‹ค, ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์€ ๊ฒฐ๊ตญ menusObservable์˜ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ๋…ธ๋Š”๊ฒƒ ์ž…๋‹ˆ๋‹ค!

ํ•˜์ง€๋งŒ, ํ˜„์žฌ๋Š” Observableํƒ€์ž…์œผ๋กœ ์ •์˜๊ฐ€ ๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•œ๋ฒˆ just๋˜๊ณ  ๋‚˜์„œ๋Š” ๊ฐ’์ด ๋ฐ”๋€Œ๋Š”๊ฒƒ ๊ฐ์ง€ํ•  ์ˆ˜ ์—†์–ด์š”!

 

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐ’์„ ๋ฐฉ์ถœ ํ•œ ์ดํ›„์—๋„ ๊ฐ’์˜ ๋ณ€๊ฒฝ์„ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” Subject๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค! 

(์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•œ๊ฑฐ๋ผ, ์‹ค์ œ ์ •์˜์™€๋Š” ์‚ฌ์•Œ์ง ๋Š๋‚Œ์ด ๋‹ค๋ฆ…๋‹ˆ๋‹ค..!)

 

๊ทธ ์ค‘์—์„œ๋„ ์šฐ๋ฆฐ PublishSubject๋ฅผ ์‚ฌ์šฉํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ, Subject๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ ์ž์ฒด๊ฐ€ ๊ณ„์† ๋ฐ”๋€Œ๋Š” ๊ฐ’์„ ๊ฐ์ง€ํ•˜๊ฒ ๋‹ค๋Š” ์˜๋ฏธ์ด๋ฏ€๋กœ

init()์„ ํ†ตํ•ด, ์ฒ˜์Œ menus๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ PublishSubject๊ฐ€ .subscribe ํ•œ๋‹ค๋ฉด

(์•„๋ž˜์˜ ์ฝ”๋“œ์—์„œ๋Š” menusObservable์ด operator์ธ .onNext()๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.)

์ดํ›„์˜ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ”๋€Œ๋Š” ๊ฐ’๋“ค์„ ๊ณ„์† ๊ด€์ฐฐ ํ•  ์ˆ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

class MenuListViewModel{
    
    var menusObservable = PublishSubject<[Menu]>()
    
    lazy var itemsCount = menusObservable
        .map{$0.map{$0.count}.reduce(0,+)}
    lazy var totalPrice = menusObservable
        .map{$0.map{$0.price * $0.count}.reduce(0,+)}
    
    init(){
        var menus : [Menu] = [
            Menu(name: "ํŠ€๊น€1", price: 100, count: 0),
            Menu(name: "ํŠ€๊น€1", price: 100, count: 0),
            Menu(name: "ํŠ€๊น€1", price: 100, count: 0),
            Menu(name: "ํŠ€๊น€1", price: 100, count: 0)
        ]
        menusObservable.onNext(menus)
    }
    
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด, ์œ„์™€ ๊ฐ™์€ MenuListViewModel์˜ ์ „์ฒด ์ฝ”๋“œ๊ฐ€ ์™„์„ฑ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ์ด์ œ, ์‹ค์ œ View๋ฅผ ๊ทธ๋ ค์ฃผ๋Š” MenuViewController์— ๊ฐ€์„œ, ์‹ค์ œ View์— ์ ์šฉ์‹œ์ผœ ์ค์‹œ๋‹ค.

 

์šฐ์„  viewDidLoad()์—์„œ Observable๋“ค์„ ๊ตฌ๋…(.subscribe)ํ•ด์ค์‹œ๋‹ค.

let viewModel = MenuListViewModel()
let disposeBag = DisposeBag()
    
override func viewDidLoad() {
    super.viewDidLoad()
        
    viewModel.itemsCount
        .subscribe(onNext: {self.itemCountLabel.text = "\($0)"})
        .disposed(by: disposeBag)
    viewModel.totalPrice
        .map{$0.currencyKR()}
        .subscribe(onNext: {self.totalPrice.text = $0})
        .disposed(by: disposeBag)
}

์ด๋ ‡๊ฒŒ viewDidLoad์— ๊ตฌ๋…์„ ๋ชจ๋‘ํ•ด๋†“์œผ๋ฉด, ์ดํ›„์— ๊ฐ’์ด ๋ฐ”๋€” ๋•Œ ๋งˆ๋‹ค ์•Œ์•„์„œ

1) totalPrice

2) itemsCount

์œ„ 2๊ฐœ๊ฐ€ View์— ์—…๋ฐ์ดํŠธ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค!

 

 

๊ทธ๋Ÿฐ๋ฐ, ์ž˜ ๋ณด๋ฉด UITableView์˜ protocol๋“ค์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋นจ๊ฐ„์ค„์ด ๋– ์žˆ์ฃ ??

UITableView์—๋Š” ์•„์ง Observable์ด ์—ฐ๊ฒฐ์ด ์•ˆ๋˜์–ด์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ƒํ™ฉ

์‚ฌ์‹ค, ์ด๋Ÿฐ DelegateํŒจํ„ด์„ ์‚ฌ์šฉํ•ด์„œ protocol์„ ๊ตฌํ˜„ํ•˜๋Š” UI๋“ค์˜ ๊ฒฝ์šฐ๋Š”, Rx๊ฐ€ ํ•„์ˆ˜์ ์ธ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

์™œ๋ƒํ•˜๋ฉด, ์ด๋ฏธ DelegateํŒจํ„ด์„ ํ†ตํ•ด์„œ ๋™์ผํ•œ ๊ธฐ๋Šฅ๋“ค์ด ๋‹ค ๊ตฌํ˜„์ด ๋˜์–ด์žˆ๊ฑฐ๋“ ์š”,,,

 

ํ•˜์ง€๋งŒ, Rx๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ€์žฅ ํฐ ์ด์œ ์ค‘์ธ ํ•˜๋‚˜์ธ ์ฝ”๋“œ์˜ ๊ฐ„๊ฒฐ์„ฑ์„ ์œ„ํ•ด์„œ๋Š” Rx๋ฅผ ์ ‘๋ชฉ์‹œ์ผœ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค!

 

 

๊ทธ๋ฆฌ๊ณ  ์ด๋Ÿฌํ•œ Delegate์— ์ •์˜๋œ protocol์„ Rx๋กœ ๋Œ€์ฒดํ•ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋ฐ”๋กœ

RxCocoa์ž…๋‹ˆ๋‹ค!!

 

 

์ด๋Ÿฌํ•œ RxCocoa๋ฅผ UITableView์—  ์ ‘๋ชฉ์‹œํ‚ค๋ฉด, ์œ„ ์‚ฌ์ง„์— ๋ณด์ด๋Š” Delegate๋ฅผ ๋ชจ์กฐ๋ฆฌ ์—†์• ๋ฒ„๋ฆด ์ˆ˜ ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค...

์ด์™€ ๊ด€๋ จ๋œ ๋‚ด์šฉ์€ ๋‹ค์Œ ํฌ์ŠคํŒ…์—์„œ ์ •๋ฆฌํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!! 

 

 

728x90
๋ฐ˜์‘ํ˜•
๋Œ“๊ธ€
๋ฐ˜์‘ํ˜•
๋งํฌ
์ตœ๊ทผ์— ์˜ฌ๋ผ์˜จ ๊ธ€
Total
Today
Yesterday