본문 바로가기

iOS

Reactor Kit View를 채택하는 VC에 bind(reactor:) 메서드가 실행되지 않음

문제 상황
- View를 채택하는 VC에 bind(reactor:) 메서드가 실행되지 않음

원인 분석

- Coordinator에서 push메서드에 reactor를 생성자에 주입하니 메서드가 실행되지 않았음

    /// 운동 편집 화면 전체 화면으로 push
    func pushEditExcerciseView(routineName: String) {
        let reactor = EditExcerciseViewReactor(routineName: routineName)
        let editExcerciseVC = EditExcerciseViewController(reactor: reactor)
        
        navigationController.pushViewController(editExcerciseVC, animated: true)
    }


해결 방안
- VC의 reactor 프로퍼티에 직접 할당하는 코드를 추가

    /// 운동 편집 화면 전체 화면으로 push
    func pushEditExcerciseView(routineName: String) {
        let reactor = EditExcerciseViewReactor(routineName: routineName)
        let editExcerciseVC = EditExcerciseViewController(reactor: reactor)
        editExcerciseVC.reactor = reactor
        navigationController.pushViewController(editExcerciseVC, animated: true)
    }


왜 이방법으로 실행이 됬는가?
- VC내부에 reactor 프로퍼티가 존재
- View 프로토콜을 까보면 bind(reator:) 메서드는 reactor가 할당되면 실행되도록 구현되어 있음 (아래 코드블럭 🔥 이모지 확인)

public protocol View: AnyObject {
  associatedtype Reactor: ReactorKit.Reactor

  /// A dispose bag. It is disposed each time the `reactor` is assigned.
  var disposeBag: DisposeBag { get set }

  /// A view's reactor. `bind(reactor:)` gets called when the new value is assigned to this property.
  var reactor: Reactor? { get set }

  /// Creates RxSwift bindings. 🔥 This method is called each time the `reactor` is assigned  🔥
  ///
  /// Here is a typical implementation example:
  ///
  /// ```
  /// func bind(reactor: MyReactor) {
  ///   // Action
  ///   increaseButton.rx.tap
  ///     .bind(to: Reactor.Action.increase)
  ///     .disposed(by: disposeBag)
  ///
  ///   // State
  ///   reactor.state.map { $0.count }
  ///     .bind(to: countLabel.rx.text)
  ///     .disposed(by: disposeBag)
  /// }
  /// ```
  ///
  /// - warning: It's not recommended to call this method directly.
  func bind(reactor: Reactor)



결론
- VC내부에 선언된 reactor 프로퍼티에 할당해줘야 정상적으로 실행되는 것
- reactor 프로퍼티를 선언하지 않고, 생성자를 통해 reactor을 할당해줘도 bind가 실행됨 (아래코드 예시)
 
이전코드

final class EditExcerciseViewController: UIViewController, View {
    
    typealias Reactor = EditExcerciseViewReactor
    
    /// 메모리 해제를 위한 DisposeBag (RxSwift)
    var disposeBag = DisposeBag()

    /// ReactorKit 또는 MVVM 패턴을 위한 리액터 객체입니다.
    private let reactor: EditExcerciseViewReactor

    /// 외부에서 리액터를 주입받아 초기화합니다.
    init(reactor: EditExcerciseViewReactor) {
        super.init(nibName: nil, bundle: nil)
        self.reactor = reactor
    }

 

수정코드

final class EditExcerciseViewController: UIViewController, View {
    
    typealias Reactor = EditExcerciseViewReactor
    
    /// 메모리 해제를 위한 DisposeBag (RxSwift)
    var disposeBag = DisposeBag()

    /// 외부에서 리액터를 주입받아 초기화합니다.
    init(reactor: EditExcerciseViewReactor) {
        super.init(nibName: nil, bundle: nil)
        self.reactor = reactor
    }