๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐ŸŽ iOS/iOS

[iOS] ReactorKit์ด๋ž€?

์•ˆ๋…•ํ•˜์„ธ์š” ์ œ์ธ์ž…๋‹ˆ๋‹ค!

์˜ค๋Š˜์€ ์ตœ๊ทผ ์ง„ํ–‰ ์ค‘์ธ ํ”„๋กœ์ ํŠธ๋ฅผ MVVM ๊ตฌ์กฐ๋กœ ๋ฆฌํŒฉํ† ๋ง์„ ํ•˜๋ฉฐ ๋„์ž…ํ•˜๊ฒŒ๋œ ReactorKit(๋ฆฌ์•กํ„ฐํ‚ท)์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋ณด๋ ค ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ”๋กœ ์‹œ์ž‘ํ• ๊ฒŒ์š”!!

ReactorKit์ด๋ž€?

ReactorKit์€ ๋ฐ˜์‘ ๋ฐ ๋‹จ๋ฐฉํ–ฅ Swift ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์œ„ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค.

MVVM๊ณผ ๊ฐ™์€ ์•„ํ‚คํ…์ฒ˜์— ๋Œ€ํ•ด ๊ณต๋ถ€ํ•ด๋ณด์‹  ๋ถ„๋“ค์ด๋ผ๋ฉด ๋Š๋ผ์…จ๊ฒ ์ง€๋งŒ ์•„ํ‚คํ…์ฒ˜๋Š” ๊ทœ๊ฒฉํ™”๋œ ํ˜•์‹์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— 

๊ฐœ๋ฐœ์ž, ํšŒ์‚ฌ๋งˆ๋‹ค ์“ฐ๋Š” ๋ฐฉ์‹์ด ์ •๋ง ๋‹ค๋ฅด๊ณ  ๋‹ค์–‘ํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ, ReactorKit์€ ํ˜•์‹์ด ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— MVVM ์•„ํ‚คํ…์ฒ˜๋ฅผ ํ”„๋กœ์ ํŠธ ๋‚ด์—์„œ ์ •ํ˜•ํ™”๋œ ๋ฐฉ์‹(๊ฐ™์€ ํ…œํ”Œ๋ฆฟ)์œผ๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

ReactorKit์„ ์‚ฌ์šฉํ•˜๋Š” ๊ณณ

 

์‹ค์ œ๋กœ ์œ„์™€ ๊ฐ™์ด ๋งŽ์€ ํšŒ์‚ฌ์—์„œ ReactorKit์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค!

 

ReactorKit์ด ์–ด๋–ค ๊ฒƒ์ธ์ง€, ์–ด๋–ค ์šฉ๋„๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ธ์ง€ ํŒŒ์•…ํ–ˆ์œผ๋‹ˆ

์–ด๋–ค ๊ตฌ์กฐ์ธ์ง€, ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ธ์ง€ ์ข€ ๋” ์ž์„ธํžˆ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!!

ReactorKit์˜ ๊ตฌ์กฐ

ReactorKit์€ ํฌ๊ฒŒ View์™€ Reactor๋กœ ์ด๋ฃจ์–ด์ ธ์žˆ์œผ๋ฉฐ
View ๋Š” Reactor ์—๊ฒŒ Action์„ ์ „๋‹ฌํ•˜๊ณ  Reactor๋Š” View์—๊ฒŒ State๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋‹จ๋ฐฉํ–ฅ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

 

  • View: ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์—ฌ์ง€๋Š” ๋ฐ์ดํ„ฐ ๋ฐ UI. View๋Š” ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ์„ Action Stream์œผ๋กœ ๋ฐ”์ธ๋”ฉํ•˜๊ณ  View์˜ State๋ฅผ ๊ฐ๊ฐ์˜ UI ์ปดํฌ๋„ŒํŠธ๋“ค์— ๋ฐ”์ธ๋”ฉํ•œ๋‹ค. View ๋ ˆ์ด์–ด๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ํฌํ•จํ•˜์ง€ ์•Š์œผ๋ฉฐ ํ•˜๋‚˜์˜ ๋ทฐ๋Š” Action Stream๊ณผ State Stream์„ ๋งคํ•‘ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ •์˜ํ•˜๊ธฐ๋งŒ ํ•œ๋‹ค.
  • Reactor: View์˜ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” UI ๋…๋ฆฝ ๊ณ„์ธต์œผ๋กœ, ViewModel๊ณผ ๊ฐ™์€ ์—ญํ• ์„ ํ•œ๋‹ค. Reactor์˜ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์—ญํ• ์€ ํ๋ฆ„ ์ œ์–ด๋ฅผ ๋ทฐ์—์„œ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๋ชจ๋“  ๋ทฐ๋Š” 1:1๋กœ ๋Œ€์‘๋˜๋Š” Reactor๋ฅผ ๊ฐ€์ง€๊ณ  ๋ชจ๋“  ๋กœ์ง์„ Reactor์— ์œ„์ž„ํ•œ๋‹ค. Reactor๋Š” ๋ทฐ์— ๋Œ€ํ•œ ์˜์กด์„ฑ์ด ์—†์œผ๋ฏ€๋กœ ์‰ฝ๊ฒŒ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

ReactorKit์„ ์‚ฌ์šฉํ•ด๋ณด์ž

Counter ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด์„œ ReactorKit์„ ์ด์šฉํ•œ MVVM ์•„ํ‚คํ…์ฒ˜ ์ ์šฉ์„ ์—ฐ์Šตํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!

์œ„์˜ ๋™์ž‘๊ณผ ๊ฐ™์ด + ๋ฒ„ํŠผ ํด๋ฆญ์‹œ ๋กœ๋”ฉ ์ธ๋””์ผ€์ดํ„ฐ๊ฐ€ 1์ดˆ ๋™์•ˆ ๋Œ์•„๊ฐ€๊ณ , ์ดํ›„์— ํ˜„์žฌ์˜ ์ˆซ์ž์—์„œ 1์ด ๋”ํ•ด์ง„ ๊ฐ’์œผ๋กœ ํ™”๋ฉด์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋Œ€๋กœ - ๋ฒ„ํŠผ ํด๋ฆญ์‹œ 1 ๋งˆ์ด๋„ˆ์Šค ๋œ ๊ฐ’์ด ์—…๋ฐ์ดํŠธ ๋˜์–ด ํ™”๋ฉด์— ํ‘œ์‹œ๋  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฐ„๋‹จํ•œ ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = (scene as? UIWindowScene) else { return }
        let window = UIWindow(windowScene: windowScene)
        let vc = CounterVC()
        vc.view.backgroundColor = .white
        window.rootViewController = vc
        
        // vc์— reactor ์ฃผ์ž…
        vc.reactor = CounterViewReactor()
        self.window = window
        window.makeKeyAndVisible()
    }
    ...
}

 

์šฐ์„ , ์Šคํ† ๋ฆฌ๋ณด๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์ฝ”๋“œ๋กœ UI ๋ฅผ ๊ตฌ์„ฑํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— SceneDelegate์—์„œ window ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด ํ™”๋ฉด์„ ์ดˆ๊ธฐํ™” ํ•ด์ฃผ๊ณ , ์•ฑ์˜ ์ฒซ ํ™”๋ฉด์ด ๋  window์˜ rootViewController๋ฅผ ์ง€์ •ํ•ด์ค๋‹ˆ๋‹ค.  

 

๊ทธ๋Ÿฐ ๋‹ค์Œ, ViewController์—๊ฒŒ reactor๋ฅผ ์ฃผ์ž…ํ•ด์ค๋‹ˆ๋‹ค.

ViewModel์„ ์‚ฌ์šฉํ•ด MVVM ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ๊ณผ ๊ฐ€์žฅ ๋‹ค๋ฅธ ๊ณผ์ •์ด ์ด๋ ‡๊ฒŒ reactor๋ฅผ ์ฃผ์ž…ํ•ด์ฃผ๋Š” ๊ณผ์ •์ธ ๊ฒƒ ๊ฐ™์€๋ฐ์š”, ReactorKit์—์„œ๋Š” ์ฃผ์ž… ๊ณผ์ •์ด ์—†๋‹ค๋ฉด ํ™”๋ฉด์ด ๋™์ž‘ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ, ํ•ด๋‹น ์˜ˆ์ œ๋Š” ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ผ ํ•˜๋‚˜์˜ ๋ทฐ๋งŒ ์กด์žฌํ•˜์ง€๋งŒ, ์—ฌ๋Ÿฌ ๋ทฐ๋กœ ์ด๋ฃจ์–ด์ง„ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์œ„์—์„œ ์„ค๋ช…ํ•œ ๊ฒƒ๊ณผ ๊ฐ™์ด View์™€ Reactor๊ฐ€ 1:1๋กœ ๋Œ€์‘๋˜๊ธฐ ๋•Œ๋ฌธ์— reactor๋ฅผ ์ฃผ์ž…ํ•ด์ฃผ๋Š” ๊ณผ์ •์„ ํ™”๋ฉด ์ „ํ™˜ ์‹œ์— ํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค!

 

์ด์ œ Reactor์™€ View๋ฅผ ๊ตฌ์„ฑํ•ด๋ด…์‹œ๋‹ค.

 

์œ„์—์„œ ์„ค๋ช…ํ–ˆ๋“ฏ์ด View๋Š” Reactor์—๊ฒŒ Action์„ ์ „๋‹ฌํ•˜๊ณ , Reactor๋Š” ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•ด์„œ View์—๊ฒŒ State๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ์ด ์˜ˆ์ œ์—์„œ View๊ฐ€ ๋ฐฉ์ถœํ•˜๋Š” Action์€?

  • + ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ
  • - ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ

์ด ๋‘๊ฐ€์ง€ ์ž…๋‹ˆ๋‹ค!

Reactor๊ฐ€ View์— ์ „๋‹ฌํ•˜๋Š” State๋Š”?

  • ์ˆซ์ž ๊ฐ’
  • ๋กœ๋”ฉ ์ธ๋””์ผ€์ดํ„ฐ์˜ ์ƒํƒœ (true or false)

์ด๋ ‡๊ฒŒ ๋‘๊ฐ€์ง€์ž„์„ ๊ธฐ์–ตํ•ด๋‘๊ณ  View์™€ Reactor๋ฅผ ๊ตฌํ˜„ํ•ด๋ด…์‹œ๋‹ค!

Reactor

๋จผ์ €, Reactor๋ถ€ํ„ฐ ๊ตฌํ˜„ํ•ด๋ด…์‹œ๋‹ค.

 

import Foundation
import RxSwift
import RxCocoa
import ReactorKit

// ViewModel์˜ ์—ญํ• ์„ ํ•˜๋Š” Reactor
// VC์—์„œ Action์„ ๋ณด๋‚ด๋ฉด Reactor์˜ ๋‚ด๋ถ€์—์„œ mutate์™€ reduce์˜ ๊ณผ์ •์„ ๊ฑฐ์ณ์„œ State๋ฅผ ๋ฐฉ์ถœํ•ด์„œ VC๋กœ ๋‹ค์‹œ ๋ณด๋ƒ„
// VC๊ฐ€ ๋ฆฌ์•กํ„ฐ์˜ state๋ฅผ ๊ตฌ๋…ํ•˜๋Š” ํ˜•ํƒœ
class CounterViewReactor: Reactor {
    let initialState = State()
    
    enum Action {
        case plus
        case minus
    }
    
    enum Mutation {
        case plusValue
        case minusValue
        case setLoading(Bool)
    }
    
    struct State {
        var value = 0
        var isLoading = false
    }
    
    // mutate()๋Š” Action ์ŠคํŠธ๋ฆผ์„ Mutation ๋‹จ์œ„๋กœ ๋ฐฉ์ถœํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•˜๋Š” Reactor์˜ ๋‚ด๋ถ€ ํ•จ์ˆ˜
    // ์˜ต์ €๋ฒ„๋ธ”: ๊ด€์ฐฐ๊ฐ€๋Šฅํ•œ ๋ฐ์ดํ„ฐ์˜ ํ๋ฆ„. Mutationํƒ€์ž…์˜ element๊ฐ€ ๋‹ด๊ธด ์˜ต์ €๋ฒ„๋ธ”์ด ๋ฆฌํ„ดํƒ€์ž…์ธ ๊ฒƒ
    func mutate(action: Action) -> Observable<Mutation> {
        switch action {
        case .plus:
            return Observable.concat([ // concat์€ ๋‘๊ฐœ ์ด์ƒ์˜ ์˜ต์ €๋ฒ„๋ธ” ์ง๋ ฌ๋กœ ์—ฐ๊ฒฐํ•˜๋Š” operator
                Observable.just(.setLoading(true)),
                Observable.just(.plusValue).delay(.seconds(1), scheduler: MainScheduler.instance),
                Observable.just(.setLoading(false))
            ])
        case .minus:
            return Observable.concat([
                Observable.just(.setLoading(true)),
                Observable.just(.minusValue).delay(.seconds(1), scheduler: MainScheduler.instance),
                Observable.just(.setLoading(false))
            ])
        }
    }
    
    // reduce()๋Š” ๋ฐฉ์ถœ๋œ Mutation ์˜ต์ €๋ฒ„๋ธ” ์ŠคํŠธ๋ฆผ์„ ๋ฐ›์•„์„œ ์ƒํƒœ๊ฐ’(State)์„ ๋ทฐ๋กœ ๋ฐฉ์ถœํ•˜๋Š” Reactor์˜ ๋‚ด๋ถ€ ํ•จ์ˆ˜
    // ์ด์ „ ์ƒํƒœ ๊ฐ’๊ณผ ์ฒ˜๋ฆฌ ๋‹จ์œ„๋ฅผ ๋ฐ›์•„ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•จ
    func reduce(state: State, mutation: Mutation) -> State {
        var newState = state
        
        switch mutation {
        case .plusValue:
            newState.value += 1
        case .minusValue:
            newState.value -= 1
        case .setLoading(let isLoading):
            newState.isLoading = isLoading
        }
        return newState
    }
}

 

CounterViewReactor๋Š” Reactor๋ผ๋Š” ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•ด์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
Reactor๋ฅผ ์ฑ„ํƒํ•˜๋ฉด Action, Mutation, State๋ฅผ ํ•„์ˆ˜์ ์œผ๋กœ ์ •์˜(์ •ํ˜•ํ™”๋œ ๊ตฌ์กฐ๋กœ ๊ตฌํ˜„) ํ•ด์ฃผ์–ด์•ผํ•˜๋ฉฐ initialState๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

 

  • Action: View๋กœ๋ถ€ํ„ฐ ๋ฐ›์„ Action์„ enum์œผ๋กœ ์ •์˜
  • Mutation: View๋กœ๋ถ€ํ„ฐ action์„ ๋ฐ›์€ ๊ฒฝ์šฐ, ์ฒ˜๋ฆฌํ•ด์•ผ ํ•  ๋ฐ์ดํ„ฐ๋“ค์„ enum์œผ๋กœ ์ •์˜
  • State: ํ˜„์žฌ ์ƒํƒœ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ, View์—์„œ ํ•ด๋‹น ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ UI ์—…๋ฐ์ดํŠธ 

 

Reactor๋Š” ๋ทฐ์—์„œ action์ด ๋“ค์–ด์˜ค๋ฉด mutate()๋ผ๋Š” ๋ฆฌ์•กํ„ฐ ๋‚ด๋ถ€ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด Observable<Mutation> ํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•˜๊ณ , reduce()๋ผ๋Š” ๋‚ด๋ถ€ ํ•จ์ˆ˜๊ฐ€ mutation๊ณผ ํ˜„์žฌ ์ƒํƒœ๋ฅผ ๋ฐ›์•„ ๋ฐ”๋€ state ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  • mutate(action:) -> Observable<Mutation> 
    :
     Action์ด ๋“ค์–ด์˜จ ๊ฒฝ์šฐ, ์–ด๋–ค ์ฒ˜๋ฆฌ๋ฅผ ํ• ๊ฒƒ์ธ์ง€ Mutation์—์„œ ์ •์˜ํ•œ ๋ฐ์ดํ„ฐ ๋‹จ์œ„๋“ค์„ ์‚ฌ์šฉํ•˜์—ฌ Observable๋กœ ๋ฐฉ์ถœ
  • reduce(state:mutation:) -> State
    : 
    ํ˜„์žฌ ์ƒํƒœ(state)์™€ ์ž‘์—… ๋‹จ์œ„(mutation)์„ ๋ฐ›์•„์„œ ์ตœ์ข… state๋ฅผ ๋ฐ˜ํ™˜. mutate(action:) -> Observable<Mutation>์ด ์‹คํ–‰๋œ ํ›„ ๋ฐ”๋กœ ํ•ด๋‹น ๋ฉ”์†Œ๋“œ ์‹คํ–‰

 

View

Reactor์—์„œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ๋กœ์ง์„ ๋ชจ๋‘ ์ฒ˜๋ฆฌํ–ˆ๋‹ค๋ฉด, ์ด๋ฅผ ์ด์šฉํ•ด ๋ทฐ์—์„œ UI๋ฅผ ์—…๋ฐ์ดํŠธํ•ด๋ด…์‹œ๋‹ค!

VC์—์„œ๋Š” View๋ผ๋Š” ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•ด ๊ตฌํ˜„ํ•ด์ฃผ์–ด์•ผ ํ•˜๋Š”๋ฐ์š”, ์ €๋Š” ์ฝ”๋“œ๋กœ ๊ตฌํ˜„ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— View๋ฅผ ์ฑ„ํƒํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

storyboard๋ฅผ ์ด์šฉํ•ด UI๋ฅผ ๊ตฌ์„ฑํ•œ๋‹ค๋ฉด, StoryboardView๋ฅผ ์ฑ„ํƒํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
(StoryboardView๋ฅผ ์ฑ„ํƒํ–ˆ์„ ๊ฒฝ์šฐ์—๋Š” ๋ทฐ๊ฐ€ ๋กœ๋“œ๊ฐ€ ๋œ ํ›„ ๋ฐ”์ธ๋”ฉ์„ ํ•ด์ค๋‹ˆ๋‹ค.)

 

import UIKit
import SnapKit
import Then
import RxSwift
import RxCocoa
import ReactorKit

class CounterVC: UIViewController {
  // UI ๊ตฌ์„ฑ
}

// MARK: - bind
// ์Šค๋ณด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด StoryboardView๋ฅผ ์ฑ„ํƒ
// ๋‘˜์˜ ์ฐจ์ด๋Š” StoryboardView๋ฅผ ์ฑ„ํƒํ–ˆ์„ ๊ฒฝ์šฐ์—๋Š” ๋ทฐ๊ฐ€ ๋กœ๋“œ๊ฐ€ ๋œ ํ›„ ๋ฐ”์ธ๋”ฉ์„ ํ•ด์ค€๋‹ค๋Š” ๊ฒƒ!
extension CounterVC: View {
    
    // ๋ฆฌ์•กํ„ฐ๊ฐ€ ์ฃผ์ž…๋˜๋ฉด bind() ๋ฐ”๋กœ ์‹คํ–‰
    func bind(reactor: CounterViewReactor) {
        bindAction(reactor)
        bindState(reactor)
    }
    
    private func bindAction(_ reactor: CounterViewReactor) {
        
        // ํ”Œ๋Ÿฌ์Šค ๋ฒ„ํŠผ
        plusBtn.rx.tap
            .map { Reactor.Action.plus }
            .bind(to: reactor.action)
            .disposed(by: disposeBag)
        
        // ๋งˆ์ด๋„ˆ์Šค ๋ฒ„ํŠผ
        minusBtn.rx.tap
            .map { Reactor.Action.minus }
            .bind(to: reactor.action)
            .disposed(by: disposeBag)
    }
    
    // Reactor์˜ state์™€ ์—ฐ๊ฒฐ
    // reactor์˜ state๋ฅผ bindํ•ด์„œ state๊ฐ€ ๋ณ€ํ• ๋•Œ๋งˆ๋‹ค ๋ฐ”๋€” UI๋ฅผ ์ง€์ •ํ•ด์ฃผ๊ณ  UI์—์„œ ๋ณ€ํ•˜๊ฒŒ๋  ๋ถ€๋ถ„๋“ค์„ ์—ฌ๊ธฐ์„œ ์ง€์ •ํ•ด์คŒ
    private func bindState(_ reactor: CounterViewReactor) {
        reactor.state.map { $0.value }
            .distinctUntilChanged()
            .map { "\($0)" }
            .bind(to: countLabel.rx.text)
            .disposed(by: disposeBag)
        
        reactor.state.map { $0.isLoading }
            .distinctUntilChanged()
            .bind(to: loadingView.rx.isAnimating)
            .disposed(by: disposeBag)
    }
}

 

์‚ฌ์šฉ์ž๊ฐ€ + ๋‚˜ - ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒ๋˜๊ฒ ์ฃ !

View๋Š” ์ด action์„ reactor์— ๋„˜๊ธฐ๊ณ , reactor์˜ state๋ฅผ ๊ตฌ๋…ํ•˜๊ณ  ์žˆ๋Š” ํ˜•ํƒœ์ž…๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ action์„ ๋ฐฉ์ถœํ•˜๊ณ  reactor๊ฐ€ ์ฒ˜๋ฆฌํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ด์šฉํ•ด UI๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ณผ์ •์€ bind(reactor: ) ๋ฉ”์†Œ๋“œ์—์„œ ๋ชจ๋‘ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค.

 

 

View์—์„œ๋Š” ReactorKit ๋‚ด๋ถ€์ ์œผ๋กœ ํ˜ธ์ถœ๋˜๋Š” bind(reactor: ) ๋ฉ”์†Œ๋“œ์—์„œ ๋ฐ”์ธ๋”ฉ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  •  bindAction(_:): View์—์„œ Reactor๋กœ ์ด๋ฒคํŠธ ๋ฐฉ์ถœ
  •  bindState(_:): Reactor์—์„œ ๋ฐ”๋€ state๋“ค์„ ๊ตฌ๋…ํ•ด์„œ UI ์—…๋ฐ์ดํŠธ

์ „์ฒด ์ฝ”๋“œ: https://github.com/jane1choi/ReactorKit-Practice

 

GitHub - jane1choi/ReactorKit-Practice

Contribute to jane1choi/ReactorKit-Practice development by creating an account on GitHub.

github.com

๋Š๋‚€์ 

ReactorKit์—์„œ ํ•„์ˆ˜์ ์œผ๋กœ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์ด ์žˆ๋‹ค๋ณด๋‹ˆ ์ •ํ•ด์ค€ ํ…œํ”Œ๋ฆฟ์„ ๋”ฐ๋ผ ์ฝ”๋“œ๋ฅผ ์งœ๋Š” ๋Š๋‚Œ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

MVVM ๊ตฌ์กฐ๋ฅผ ์ฒ˜์Œ ๊ตฌ์„ฑํ•˜๋‹ค๋ณด๋ฉด ViewModel์„ ์–ด๋–ป๊ฒŒ ๊ตฌ์„ฑํ•ด์„œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋ถ„๋ฆฌํ• ์ง€ ๋ง‰๋ง‰ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ReactorKit์˜ ๊ฐ€์ด๋“œ๋ผ์ธ์„ ๋”ฐ๋ผ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ทฐ๋ฅผ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด MVVM ์ดˆ์‹ฌ์ž๊ฐ€ ์‹œ์ž‘ํ•ด๋ณด๊ธฐ์— ์ข‹์„ ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“œ๋„ค์š”!

๊ทธ๋ฆฌ๊ณ  ํ•œ ํ”„๋กœ์ ํŠธ์—์„œ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์งค ์ˆ˜ ์žˆ๋‹ค๋ณด๋‹ˆ ์ฝ”๋“œ ๋ฆฌ๋ทฐ ํ•˜๊ธฐ์—๋„ ํŽธํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค!

๋ฆฌ์•กํ„ฐํ‚ท์œผ๋กœ MVVM ์•„ํ‚คํ…์ฒ˜ ์ ์šฉ ์—ฐ์Šต์„ ์ข€ ํ•ด๋ณด๊ณ  ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๋ถ„๋ฆฌ์— ์ต์ˆ™ํ•ด์ง€๋ฉด ๋ฆฌ์•กํ„ฐํ‚ท์„ ๋–ผ๊ณ  ๋ทฐ๋ชจ๋ธ์„ ๋งŒ๋“ค์–ด MVVM ๊ตฌ์กฐ๋กœ ๋งŒ๋“œ๋Š” ์—ฐ์Šต์„ ํ•œ๋ฒˆ ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค..

 


[์ฐธ๊ณ  ์ž๋ฃŒ]

 

GitHub - ReactorKit/ReactorKit: A library for reactive and unidirectional Swift applications

A library for reactive and unidirectional Swift applications - GitHub - ReactorKit/ReactorKit: A library for reactive and unidirectional Swift applications

github.com

 

[iOS - swift] 1. ReactorKit - ๊ฐœ๋…

1. ReactorKit - ๊ฐœ๋… 2. ReactorKit - ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ• (Storyboard ์‚ฌ์šฉ, IBOutlet ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ•) 3. ReactorKit - `TaskList ๊ตฌํ˜„`, ํ…œํ”Œ๋ฆฟ (template), ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ transform(mutation:) 4. ReactorKit - `Task..

ios-development.tistory.com

 

[iOS] ReactorKit ์•Œ์•„๋ณด๊ธฐ

Reactorkit์ด ๋ญ˜๊นŒ ?

velog.io