개발/Swift

[Swift] ReactorKit 사용시 고민할 부분 (비즈니스 로직, Pulse )

덤벨로퍼 2024. 12. 21. 19:16

View 이벤트와 비즈니스 로직 연동 고민

다음 페이지 진입을 할지 말지가 비즈니스 로직의 결과값에 의해 결정 되어서 바로 바인딩을 할수가 없는경우

 

필요한 로직은 다음과 같다.

  1. 버튼 클릭
  2. reactor -> usecase 에서 비즈니스 로직 이후 Bool 리턴 or 에러 리턴
  3. 에러인경우 에러 노출 , true 인경우 API 호출
  4. 응답 값 가지고 다음 페이지 진입

클릭 바인딩에서 보통 다음 페이지 진입을 하는게 일반적 이지만

다음페이지 진입을 할지 말지가 비즈니스 로직의 결과값에 의존하기 때문에 바로 바인딩을 할수가 없다.

 

따라서 

로직 결과값이 State를 변경시키며

VC에서는 State 바인딩을 통해 다음 페이지 진입 하는식으로 작업

버튼 클릭 -> 로직 수행 (vc -> reactor -> usecase)

로직 에러 -> 에러 노출 (reactor -> vc)
로직 응답 -> UI 수행

 

State 바인딩이 모두 도는 경우

        reactor.state.map { $0.viewData }
            .distinctUntilChanged()

보통 이런 식으로 State 바인딩을 처리함

distinctUntilChanged()를 통해서 값이 변경 된 경우에만 로직을 타도록 유도함

reactor.state를 바인딩하기 떄문에

State.a State.b 가 있는경우 state 중 아무거나 바뀌어도 일단 이벤트가 돌기 떄문이다.

 

그런데

값이 변하지 않고도 로직을 수행해야 하는경우가 있음,

문제는 distinctUntilChanged 를 써서 같은 값 이벤트를 막았을때

버튼클릭 → api 호출 → 응답 → 바인딩 한경우

같은 응답 값이 올수 있기 떄문에 원하는대로 이벤트 호출이 안됨

 

 

값을 사용하고 값을 nil로 초기화 하여서 다른 state 변경시 방어 하도록 작업할수 있다.

        reactor.state.map { $0.moveToReportWrite }
            .compactMap({ $0 })

moveToReportWrite 값이 compactMap 을 통해 nil이 걸리지게 되었다.

그러므로 값을 사용후 nil로 초기화 하여 이벤트 방어

reactor.state.map { $0.moveToReportWrite }
      .compactMap({ $0 })
      .bind { [weak self] useWheather, useNoticeTalk in
          self?.presentWriteVC(useWheather: useWheather, useNoticeTalk: useNoticeTalk)
          self?.reactor?.action.onNext(.clearTempState)
      }.disposed(by: disposeBag)

clearTempState 액션을 통해 초기화가 필요한 1회성 상태 모든 값 초기화

 

 

하지만 이것보다 더 깔끔한 방법은 Pulse 를 쓰는것,

챗지피티가 Pulse 쓰는거랑 distinctUntilChanged() 랑같다고 설명했느데

Pulse는 값이 안바뀌어도 이벤트 방출됨, state 값 변경만 되면 됨

 

 struct State {
  @Pulse var viewData: ViewData?
  }
  
//VC
reactor.pulse(\\.$viewData)
  .compactMap { $0 }
  .bind { [weak self] viewData in
      self?.title = viewData.title
  }.disposed(by: disposeBag)