iOS ์—์„œ MVI ํŒจํ„ด ์ ์šฉํ•˜๊ธฐ #1

์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ์ž๋ผ๋ฉด ๋ˆ„๊ตฌ๋‚˜ ๋“ค์–ด ๋ดค์„ MVC, MVP, MVVM ๋“ฑ์˜ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋””์ž์ธ ํŒจํ„ด์ด ์žˆ์Šต๋‹ˆ๋‹ค.

iOS๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ MVC ์ฐจ์šฉ ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— MVC ๊ตฌ์กฐ๋Š” ๋‹ค๋“ค ์ต์ˆ™ํ•˜๊ฒŒ ์‚ฌ์šฉ ์ค‘์ผ ๊ฒ๋‹ˆ๋‹ค.
(View์™€ ViewController๋ฅผ ์‚ฌ์šฉํ•˜๋Š” MVC๋ผ๊ณ  ์ƒ๊ฐ์‹œ๋Š”๋ถ„๋„ ๊ณ„์‹œ์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” MVP ํŒจํ„ด ์ž…๋‹ˆ๋‹ค.)

ํ•ด๋‹น ํŒจํ„ด์„ MVC๋ผ๊ณ  ๋ถ€๋ฅด์‹œ๋Š” ๋ถ„๋„ ๊ณ„์…”์„œ ํŽธ์˜์ƒ MVC๋ผ๊ณ  ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ MVC ๊ตฌ์กฐ๋Š” Controller๊ฐ€ ๊ณผ๋„ํ•˜๊ฒŒ ๋น„๋Œ€ํ•ด ์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๊ณ , Dooray์•ฑ๋„ MVC-> MVVM์œผ๋กœ ์ „ํ™˜ ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ Dooray์•ฑ์€ ํŠน์„ฑ์ƒ ํ•œ ํ™”๋ฉด์—์„œ ๋งŽ์€ APIํ˜ธ์ถœ๊ณผ ์‚ฌ์šฉ์ž ์กฐ์ž‘์ด ์ผ์–ด ๋‚˜๊ณ  ์ด์— ๋”ฐ๋ผ UI๊ฐ€ ์ž์ฃผ ๋ณ€๊ฒฝ ๋˜๋Š”๋ฐ ๋น„๋™๊ธฐ ๋™์ž‘๋“ค์ด ๋™์‹œ์— ์ผ์–ด ๋‚˜๋Š”๊ฒฝ์šฐ ์ •ํ™•ํ•œ ํ™”๋ฉด ์ƒํƒœ๋ฅผ ํ‘œ์‹œ ํ•˜๋Š”๋ฐ ์–ด๋ ค์›€์„ ๊ฒช์—ˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฅผ ๊ทน๋ณต ํ•˜๊ณ ์ž ์•ฝ 3๋…„ ์ „๋ถ€ํ„ฐ MVI ํŒจํ„ด์„ ์ ์šฉ ํ•˜์˜€๊ณ  ํ˜„์žฌ๊นŒ์ง€ ํ™œ์šฉ ์ค‘์ž…๋‹ˆ๋‹ค. ๋‹ค์†Œ ๋Šฆ์€ ๊ฐ์ด ์žˆ์ง€๋งŒ MVI ํŒจํ„ด ์ ์šฉ ๋ฐฉ๋ฒ•๊ณผ ์žฅ๋‹จ์ ๋“ฑ์„ ๊ณต์œ ํ•˜๊ณ ์ž ๊ธ€์„ ๋‚จ๊ธฐ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

MVI๋ž€?

iOS ๊ฐœ๋ฐœ์ž ๋ถ„์ด์‹œ๋ผ๋ฉด ๋‹ค์†Œ ์ƒ์†Œ ํ•  ์ˆ˜๋„ ์žˆ๋Š”๋ฐ์š”. Model-View-Intent์˜ ์•ฝ์ž๋กœ ๋‹จ๋ฐฉํ–ฅ ์•„ํ‚คํ…์ฒ˜ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

๊ตฌ์กฐ๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ทธ๋ ค ๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๊ฐ ์š”์†Œ์˜ ์—ญํ• ์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

View: ์‚ฌ์šฉ์ž์—๊ฒŒ ์ œ๊ณต๋˜์–ด ๋ณด์—ฌ ์ง€๋Š” UI ๋ถ€๋ถ„์œผ๋กœ ์ƒํƒœ(state)๋ฅผ ์ž…๋ ฅ ๋ฐ›์•„ ํ™”๋ฉด์— ์ถœ๋ ฅ

Intent: ์•ฑ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝ ํ•˜๋ ค๋Š” ์˜๋„๋ฅผ ์˜๋ฏธํ•˜๋ฉฐ ์‚ฌ์šฉ์ž์˜ ์ƒํ˜ธ์ž‘์šฉ์œผ๋กœ ๋ฐœ์ƒํ•œ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝ ํ•˜๋Š” ๋™์ž‘์„ ํ•ฉ๋‹ˆ๋‹ค.

Model(State): ์•ฑ์˜ ์ƒํƒœ๋ฅผ ์˜๋ฏธํ•˜๋ฉฐ MVI์—์„œ๋Š” ํ•˜๋‚˜์˜ ์ƒํƒœ๋งŒ์„ ๊ฐ–์œผ๋ฉฐ imutableํ•œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋กœ ์ž‘์„ฑ ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. intent๋ฅผ ํŠธ๋ฆฌ๊ฑฐ ํ•˜์—ฌ ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ๋งŒ์ด State๋ฅผ ๋ฐ”๊พธ๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

๋‹จ๋ฐฉํ–ฅ ์•„ํ‚คํ…์ฒ˜?

MVI์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋‚ด์šฉ์ด ๋‹จ๋ฐฉํ–ฅ ์•„ํ‚คํ…์ฒ˜๋ผ๋Š”๊ฒƒ์ด ์•„๋‹๊นŒ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ ๋‹จ๋ฐฉํ–ฅ ์ดํ‚คํ…์ฒ˜๋ž€ ๋ฌด์—‡์ผ๊นŒ์š”?

๋‹จ๋ฐฉํ–ฅ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” MVI์—์„œ์˜ ์ด๋ฒคํŠธ ํ๋ฆ„์„ ๋จผ์ € ์ดํ•ด ํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ์œ ์ €์˜ ์ธํ„ฐ๋ ‰์…˜์ด ๋ฐœ์ƒ(ํ™”๋ฉด ํ„ฐ์น˜ ๋“ฑ์˜ ๋™์ž‘)
  2. Intent๋กœ ํ•ด๋‹น Event๊ฐ€ ์ „๋‹ฌ
  3. Intent๊ฐ€ ์ƒํ™ฉ์— ๋งž๋Š” Model(State)์„ ์—…๋ฐ์ดํŠธ
  4. View์—์„œ๋Š” Model(State)์„ ๊ด€์ฐฐํ•˜๊ณ  ์žˆ๋‹ค๊ฐ€ ๋ณ€ํ™”๊ฐ€ ์ผ์–ด ๋‚  ๋•Œ ๋งˆ๋‹ค ์ด๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ ์ƒํƒœ์— ๋งž๋Š” ํ™”๋ฉด์„ ๋ Œ๋”๋ง ํ•ฉ๋‹ˆ๋‹ค.

์ด๋•Œ ๊ฐ€์žฅ์ค‘์š” ํ•œ๊ฒƒ์€ Model(State)๊ฐ€ View๋กœ ์ „๋‹ฌ ๋ ๋•Œ Imutableํ•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋Š” View์—์„œ๋Š” Model(State)๋ฅผ ์ง์ ‘์ ์œผ๋กœ ์ˆ˜์ • ํ•  ๋ฐฉ๋ฒ•์€ ์กด์žฌ ํ•˜์ง€ ์•Š์Œ์„ ์˜๋ฏธํ•˜๋ฉฐ Model(State)์„ ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Intent๋ฅผ ๊ฑฐ์ณ์•ผ๋งŒ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ Intent์— ์„œ๋Š” View์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๊ฐ–๊ณ  ์žˆ์ง€ ์•Š์œผ๋ฉฐ Intent์—์„œ View๋กœ Event๋ฅผ ์ „๋‹ฌ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๊ฐœ๋…์ ์ธ ์ด์•ผ๊ธฐ ๋งŒ์œผ๋กœ๋Š” MVI์˜ ๋‹จ๋ฐฉํ–ฅ ๊ตฌ์กฐ์— ๋Œ€ํ•ด์„œ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์šธ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. Dooray์—์„œ๋Š” MVI ํŒจํ„ด์„ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋ช‡๊ฐ€์ง€ ์˜คํ”ˆ์†Œ์Šค ํ”„๋ ˆ์ž„ ์›Œํฌ๋“ค์„ ๊ฒ€ํ† ํ•˜์˜€๊ณ  ReactorKit์„ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ • ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ReactorKit์„ ์ ์šฉ ํ•˜๋ฉด์„œ ๋” ์ž์„ธํžˆ ์•Œ์•„ ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.



ReactorKit?

Git ๋งํฌ: https://github.com/ReactorKit/ReactorKit

ReactorKit์€ Swift์™€ Objective-C๊ธฐ๋ฐ˜์œผ๋กœ ์ž‘์„ฑ ๋˜์–ด ์žˆ์œผ๋ฉฐ iOS, Mac OS ๋“ฑ์—์„œ MVI ํŒจํ„ด์„ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ๋‹จ๋ฐฉํ–ฅ, ๋ฐ˜์‘ํ˜• Framework์ž…๋‹ˆ๋‹ค. RxSwift์— ์˜์กด์„ฑ์„ ๊ฐ–๊ณ  ์žˆ์–ด Rx์— ๋Œ€ํ•œ ์„ ํ–‰ ์ง€์‹์ด ํ•„์ˆ˜ ์ ์ž…๋‹ˆ๋‹ค.

ReactorKit์—์„œ๋Š” MVI์˜ ๊ฐ ์š”์†Œ์˜ ์ด๋ฆ„์„ ์ข€ ๋‹ค๋ฅด๊ฒŒ ์ง€์นญํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋จผ์ € MVI์˜ ๊ตฌ์กฐ๋ฅผ ๊ทธ๋ฆผ์œผ๋กœ ๊ทธ๋ ค ๋ณด๋ฉด ์•„๋ž˜ ์™€๊ฐ™์Šต๋‹ˆ๋‹ค.

์œ„ ๊ทธ๋ฆผ์„ ReactorKit์— ๋Œ€์‘ํ•˜๋Š” ํ˜•ํƒœ๋กœ ๋‹ค์‹œ ๊ทธ๋ ค ๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

View: MVI์˜ View์™€ ReactorKit View๋Š” ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ReactorKit์—์„œ View๋Š” ์–ด๋– ํ•œ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง๋„ ๊ฐ–๊ณ  ์žˆ์ง€ ์•Š์œผ๋ฉฐ ์•„๋ž˜ ์™€ ๊ฐ™์ด View Protocol์„ ํ™•์žฅํ•˜์—ฌ ์‚ฌ์šฉ ํ•ฉ๋‹ˆ๋‹ค.

//View protocol์„ ๊ตฌํ˜„
class ProfileViewController: UIViewController, View {
  var disposeBag = DisposeBag()
}

profileViewController.reactor = UserViewReactor() // Reactor ๊ตฌํ˜„์ฒด๋ฅผ ์ฃผ์ž…

View๋Š” UIEvent๋“ค์„ Action์œผ๋กœ ๋ณ€ํ™˜ ํ•˜์—ฌ Reactor.action์— ๋ฐ”์ธ๋”ฉ ํ•ด์ฃผ๊ณ  State๋ฅผ ๊ตฌ๋…ํ•˜๊ณ  UI์ฝคํฌ๋„ŒํŠธ์— ๋ฐ”์ธ๋”ฉ ํ•˜์—ฌ ํ™”๋ฉด์— ๋ Œ๋”๋งํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

func bind(reactor: ProfileViewReactor) {
  // action (View -> Reactor)
  refreshButton.rx.tap.map { Reactor.Action.refresh }
    .bind(to: reactor.action)
    .disposed(by: self.disposeBag)

  // state (Reactor -> View)
  reactor.state.map { $0.isFollowing }
    .bind(to: followButton.rx.isSelected)
    .disposed(by: self.disposeBag)
}

Action: View์—์„œ Reactor๋กœ ์ „๋‹ฌ ๋˜๋Š” Event๋ฅผ ReactorKit์—์„œ๋Š” Action์œผ๋กœ ์ง€์นญ ํ•ฉ๋‹ˆ๋‹ค.

Reactor: MVI์˜ Intent์— ๋Œ€์‘ํ•˜๋Š” ๊ฐœ๋…์œผ๋กœ ๋‚ด๋ถ€์ ์œผ๋กœ UI์™€๋Š” ๋…๋ฆฝ์ ์ธ ๋ ˆ์ด์–ด์— ์†ํ•ด ์žˆ์œผ๋ฉฐ State๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ๊ด€๋ฆฌ ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ๋ทฐ์—๋Š” ํ•ด๋‹น Reactor๊ฐ€ ์žˆ์œผ๋ฉฐ ๋ชจ๋“  ๋กœ์ง์„ ํ•ด๋‹น Reactor์— ์œ„์ž„ํ•ฉ๋‹ˆ๋‹ค. Reactor๋Š” ๋ทฐ์— ์ข…์†๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์‰ฝ๊ฒŒ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Reactor๋ฅผ ๊ตฌํ˜„ ํ•˜๊ธฐ์œ„ํ•ด์„œ๋Š” ReactorKit์— ์ •์˜ ๋˜์–ด ์žˆ๋Š” Reactor Protocol์„ ์•„๋ž˜์™€ ๊ฐ™์ด ํ™•์žฅ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

Action, Mutation, State์˜ ์„ธ๊ฐ€์ง€ ๋ฐ์ดํ„ฐ ์œ ํ˜•์„ ์ •์˜ ํ•ด์•ผ ํ•˜๋ฉฐ ์ตœ์ดˆ ์ƒํƒœ๋ฅผ ์˜๋ฏธํ•˜๋Š” initialState๋ฅผ ์ •์˜ ํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

// <์ฝ”๋“œ1.>
class ProfileViewReactor: Reactor {
  // represent user actions
  enum Action {
    case refreshFollowingStatus(Int)
    case follow(Int)
  }

  // represent state changes
  enum Mutation {
    case setFollowing(Bool)
  }

  // represents the current view state
  struct State {
    var isFollowing: Bool = false
  }

  let initialState: State = State()
}

์•ž์—์„œ Action์€ ์‚ฌ์šฉ์ž ์ƒํ˜ธ ์ž‘์šฉ์„ ๋‚˜ํƒ€๋‚ด๊ณ  State๋Š” ํ™”๋ฉด์„ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•œ ์ƒํƒœ๋ผ๊ณ  ์ด์•ผ๊ธฐ ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ Mutation์ด๋ผ๋Š” ์ƒˆ๋กœ์šด ๊ฐœ๋…์ด ๋“ฑ์žฅํ•˜๋Š”๋ฐ์š”. ๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๋ฉด Action๊ณผ State์˜ ์ค‘๊ฐ„ ๋‹ค๋ฆฌ์—ญํ• ์„ ํ•˜๋Š” ์ด๋ฒคํŠธ๋ผ๊ณ  ๋ณด์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ๊ทธ๋ฆผ์„ ๋ณด๋ฉด์„œ ๋” ์ž์„ธํ•˜๊ฒŒ ์„ค๋ช… ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


View์—์„œ๋Š” Action์„ ๋งŒ๋“ค์–ด์„œ Reactor์— ์ „๋‹ฌํ•˜๊ฒŒ๋˜๊ณ  ์ด๋•Œ Action์„ ์ˆ˜์‹  ํ•˜๋Š”๊ณณ์ด mutate() ํ•จ์ˆ˜ ์ž…๋‹ˆ๋‹ค.

mutate() ํ•จ์ˆ˜๋Š” API์š”์ฒญ ๊ฐ™์€ ๋น„๋™๊ธฐ ์ž‘์—…๋“ค์„ ์ฒ˜๋ฆฌ ํ•˜๊ฒŒ ๋˜๊ณ  ํ•ด๋‹น ์ž‘์—…์ด ์™„๋ฃŒ ๋˜๋ฉด Mutation์„ ๋ฐœ์ƒ ์‹œ์ผœ reduce() ํ•จ์ˆ˜๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.


SideEffect: ์™ธ๋ถ€ ์„ธ๊ณ„์™€ ์˜ํ–ฅ์„ ์ฃผ๊ณ  ๋ฐ›๋Š” ์ผ๋ จ์˜ ๊ณผ์ •์œผ๋กœ APIํ†ต์‹ , DB ์‚ฌ์šฉ ๋“ฑ์ด ์ด์— ์†ํ•œ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋Œ€๋ถ€๋ถ„์˜ SideEffect๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์œผ๋กœ ์ˆ˜ํ–‰ ๋˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ SideEffect๋Š” ReactorKit์—์„œ๋Š” mutate()ํ•จ์ˆ˜์—์„œ๋งŒ ์ทจ๊ธ‰ ํ•˜๋„๋ก ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

func mutate(action: Action) -> Observable<Mutation> {
  switch action {
  case let .refreshFollowingStatus(userID): // receive an action
    return UserAPI.isFollowing(userID) // create an API stream
      .map { (isFollowing: Bool) -> Mutation in
        return Mutation.setFollowing(isFollowing) // convert to Mutation stream
      }

  case let .follow(userID):
    return UserAPI.follow()
      .map { _ -> Mutation in
        return Mutation.setFollowing(true)
      }
  }
}


func reduce(state: State, mutation: Mutation) -> State {
  var state = state // create a copy of the old state
  switch mutation {
  case let .setFollowing(isFollowing):
    state.isFollowing = isFollowing // manipulate the state, creating a new state
    return state // return the new state
  }
}

์ด๋Ÿฌํ•œ ํ๋ฆ„์„ ๋ณด๋ฉด ๋ช‡๊ฐ€์ง€ ์˜๋ฌธ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1. ๋น„๋™๊ธฐ ์ž‘์—…์€ ์™œ mutate()ํ•จ์ˆ˜์—์„œ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š”๊ฐ€?

-> ๋น„๋™๊ธฐ ์ž‘์—…์€ ์‹คํ–‰๋œ ์Šค๋ ˆ๋“œ์™€ ์‘๋‹ต ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์ผํ•จ์„ ๋ณด์žฅ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์ด ๋ง์€ ๋งŒ์•ฝ reduce()์—์„œ ์—ฌ๋Ÿฌ๊ฐœ์˜ ๋น„๋™๊ธฐ ์ž‘์—…์ด ์ˆ˜ํ–‰ ๋˜๋Š” ๊ฒฝ์šฐ ๋™์‹œ์— ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์—์„œ state์— ์ ‘๊ทผ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ Action -> Reactor -> State์˜ ์ŠคํŠธ๋ฆผ์— ์น˜๋ช…์ ์ธ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค๋ฉด A์ž‘์—…์ด A์Šค๋ ˆ๋“œ์—์„œ ๋™์ž‘ํ•˜๊ณ , B์ž‘์—…์ด B์Šค๋ ˆ๋“œ์—์„œ ์ž‘๋™ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ์‹œ๋‹ค. A์ž‘์—…์ด ์™„๋ฃŒ๋˜์–ด A์Šค๋ ˆ๋“œ์—์„œ State๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜๋Š” ์ค‘ B์Šค๋ ˆ๋“œ์ž‘์—…์ด ์™„๋ฃŒ ๋˜์–ด ๋™์‹œ์— B์Šค๋ ˆ๋“œ์—์„œ State์— ์ ‘๊ทผํ•˜๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒ ํ•  ์ˆ˜ ์žˆ๊ณ  ์ด๋Š” State์˜ ์›์ž์„ฑ์„ ๋ณด์žฅ ํ•  ์ˆ˜ ์—†๊ฒŒ ๋จ ์„ ์˜๋ฏธ ํ•ฉ๋‹ˆ๋‹ค.

์ด์— ReactorKit์—์„œ๋Š” ๋‹จ์ผ ์Šค๋ ˆ๋“œ์—์„œ๋งŒ ๋™์ž‘ํ•˜๋Š” reduce()ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์„œ state์— ๋™์‹œ์— ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ์ ‘๊ทผ ํ•˜๋Š” ์ƒํ™ฉ์„ ๋ง‰๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

2. reduce() ํ•จ์ˆ˜์—์„œ์™œ ์ƒˆ๋กœ์šด state๋ฅผ ์ƒ์„ฑํ•˜๋Š”๊ฐ€?

-> ์ดˆ๋ฐ˜์— State๋Š” imutableํ•˜๋‹ค๊ณ  ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์œ„์˜ <์ฝ”๋“œ1> ์„ ๋ณด์‹œ๋ฉด Reactor์˜ ๊ตฌํ˜„์ฒด์—์„œ State๋Š” Struct๋กœ ์‚ฌ์šฉ ํ•˜๋Š”๊ฒƒ์„ ๋ณด์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” Reactor-> View๋กœ State๊ฐ€ ์ „๋‹ฌ ๋˜๋Š”๊ฒฝ์šฐ ๋ณต์‚ฌ๊ฐ€ ์ผ์–ด ๋‚˜๊ฒŒ ๋˜๊ณ  View์—์„œ State๋ฅผ ๋ฐ”๊พธ๋”๋ผ๋„ ์ด๋Š” Reactor๋‚ด๋ถ€์˜ State๋Š” ๋ฐ”๋€Œ์ง€ ์•Š์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, View์—์„œ๋Š” state์— ๋Œ€ํ•œ ์ง์ ‘์ ์ธ ์ฐธ์กฐ๋ฅผ ๊ฐ–๊ธฐ ์•Š๊ฒŒ ๋˜์–ด View์—์„œ state๋ฅผ ๋ฐ”๊พธ๋Š” ์ž ์žฌ์ ์ธ ์œ„ํ—˜์œผ๋กœ ๋ถ€ํ„ฐ ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค.

State: MVI ์˜ Model ๋กœ์„œ View๋Š” State๋ฅผ ์ฐธ๊ณ  ํ•˜์—ฌ ํ™”๋ฉด์„ ๋ Œ๋”๋ง ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ReactorKit ์—์„œ๋Š” ๋ณดํ†ต State๋Š” ๊ตฌ์กฐ์ฒดํ˜•ํƒœ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์ด๋Š” state๋ฅผ imutableํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ํšจ๊ณผ๋ฅผ ๊ฐ–๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ ๊นŒ์ง€ ๋Œ€๋žต์ ์ธ MVIํŒจํ„ด๊ณผ ReactorKit์˜ ๋™์ž‘ ๋ฐฉ์‹์— ๋Œ€ํ•ด ์•Œ์•„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์—๋Š” Dooray์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ์˜ˆ์‹œ๋กœ transform๊ณผ 1ํšŒ์„ฑ ์ด๋ฒคํŠธ ๋“ค์„ ๋‹ค๋ฃจ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ  ๋ฌธํ—Œ:
https://github.com/ReactorKit/ReactorKit

์ด ํฌ์ŠคํŠธ๋ฅผ ๊ณต์œ ํ•ด์ฃผ์„ธ์š”
ํ˜ธ์ด
ํ˜ธ์ด

๋‘๋ ˆ์ด๋ชจ๋ฐ”์ผ์„œ๋น„์Šค ๊ฐœ๋ฐœํŒ€ ๋ฆฌ๋“œ.

Articles: 1

์˜๊ฒฌ ๋‚จ๊ธฐ๊ธฐ

0