본문 바로가기

Computer

[RxSwift] `UITextField.rx.text` 프로퍼티의 '예상치 못한 요소 방출' 이슈

문제:

textField.rx.text.orEmpty.asDriver()
    .drive(with: self) { owner, text in
        print("text")
    }
    .disposed(by: disposeBag)

그림 1. `text` controlProperty 구독 예시

 

그림 1 처럼 `UITextField` 의 `text` controlProperty 를 구독한 상황에서 현재 화면이 dismiss 될때 구독 클로저가 한 번 더 실행되는 것 같은 현상이 발생.

 

 

해결과정:

  1. 문제의 구독과 연관 있는 다른 구독을 살펴보며 원인 파악
    -> 아무리 봐도 문제가 없음(원인을 모르겠음)
  2. 여기저기 `debug()` operator 를 사용해가며 문제 원인 파악
    -> 구독 문제가 아니라 `text` controlProperty 에서 직접적으로 element 가 한 번 더 방출되는 것을 확인
  3. ["UITextField", "when dismissed", "RxSwift", "emit event"] 키워드로 구글 검색
    -> https://stackoverflow.com/questions/51864508/rxswift-bind-on-textfield-sending-next-after-pushing-another-view 이 글을 찾음
    -> `editingDidEnd` 이벤트가 존재한다는 단서를 얻고 `text` controlProperty 구현을 다시 살펴봐야겠다고 판단
    -> 요소 방출 이벤트가 [.allEditingEvents, .valueChanged] 로 설정되어 있는것을 확인
    -> view 가 dismiss 되면서 트리거가 되는 Event 를 발생시키진 않는지 확인이 필요하다고 판단
  4. 새 프로젝트를 생성하여 하나하나씩 문제 상황과 비슷하게 만들며 원인 파악
    -> `becomeFirstResponder()` 함수 호출을 추가했을 때 문제 상황 재현에 성공
    -> 드디어 퍼즐이 풀리며 원인 파악에 성공!

 

원인:

`UITextField` 는 입력을 시작할 때와 같이 입력을 마치고 First responder 를 내려놓을 때도 editing event 가 발생하여 요소를 방출했던 것이였다.(아마도 `editingDidEnd` 이벤트)

 

 

해결:

- 사실 `text` property 에 `distinctUntilChanged()` 함수를 사용하면 문제가 해결되는건 알고 있었다. 하지만 원인을 알아내는 것이 나한텐 더 중요하므로 이번엔 정확한 원인을 파악했다는 것에 가치를 두어야겠다.

- 아마도 이번 문제 상황(dismiss)이 아닌 다른 케이스에서 요소가 여러번 방출된다면 트리거가 되는 이벤트를 생성하고 있다는 가능성을 생각해야겠다.