Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

teunteun2

[Swift] ReactorKit 본문

iOS

[Swift] ReactorKit

teunteun2 2022. 5. 10. 23:32

View <-> Reactor

그 사이에 Action stream 과 State stream 를 주고받는다

View -> (Action) -> Reactor

Reactor -> (State) -> View

 

디자인 의도

1. Testability -> View로부터 비즈니스 로직을 분리하기 위함

2. Small

3. Less Typing

 

-- View  --

(아마 프로젝트에서는 ViewController & Cell 을 지칭할듯)

 

- 뷰는 그저 actionStream과 stateStream을 map 할지 를 정의하는 부분 (보내고 받기만 한다는 뜻인듯)

1 뷰를 정의할 땐, 리액트킷에 정의되어 있는 View 프로토콜을 채택하면 된다.

2 View 프로토콜을 채택하면 그 클래스는 자동으로 reactor라는 프로퍼티를 갖게됨. 

3 이 프로퍼티에 나중에 생성하게 될 Reactor를 inject 해준다

class ProfileViewController: UIViewController, View {
  var disposeBag = DisposeBag()
}

profileViewController.reactor = UserViewReactor() // inject reactor

4 할당해준 reactor 프로퍼티가 변경되었을 때 bind(reactor:) 이 호출된다. 이 메서드를 통해 action stream과 state stream의 bindings를 정의해주는 것임 !

 

-- Reactor --

- 리액터는 View의 state를 관리하는 UI-independent 계층이다

- 리액터의 가장 중요한 역할은 플로우를 뷰로부터 분리하는 것

- 모든 뷰는 응답하는 Reactor를 가지고 있고, 모든 로직을 Reactor에 위임한다.

- Reactor는 반대로 뷰에게 의존성이 전혀 없기 때문에, 쉽게 테스트 가능하다고 함 

 

1 Reactor 프로토콜을 채택해서 생성한다. 이 프로토콜은 Action, Mutation, State 세 가지를 정의해주어야 함

2 ++ 추가로 initialState라는 프로퍼티도 필요함

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 : User interaction

- State : View state

- Mutation : Action & State 둘 간의 bridge

3 Reator은 Action stream을 State stream으로 mutate() , reduce() 두 단계를 거쳐 변환한다

 

 

-- mutate() --

- mutate()은 Action을 받아서 Observable<Mutation>을 return 하는 역할

- action을 정의할 때 enum으로 정의하기 때문에 mutate()에서 매개변수로 받아와 switch 문으로 각 action을 처리

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)
      }
  }
}

 

-- reduce() --

- 이전 State & Mutation 을 바탕으로 새로운 State를 만드는 역할

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
  }
}

- 아하 그러니까 mutate() 메서드에서 action을 mutation으로 바꾼 것을 바탕으로 reduce() 메서드에서 새로운 state로 바꿔준다는 말인듯