Notice
Recent Posts
Recent Comments
Link
«   2024/06   »
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
Tags
more
Archives
Today
Total
관리 메뉴

일왓록(日What錄)

[TroubleShooting][RxSwift]TextField의 중복 값 해결: distinctUntilChanged 본문

iOS/TroubleShooting

[TroubleShooting][RxSwift]TextField의 중복 값 해결: distinctUntilChanged

일왓 2024. 1. 11. 15:40

⚠️발생 문제

회원가입에서 이메일 중복 검사, 비밀번호 유효성 검사, 비밀번호 재확인 검사, 닉네임 글자수 확인등의 조건을 확인하고 서버로 API요청을 하는 로직을 개발하던 중, 이메일 중복 검사를 확인했음에도 다시 확인하라는 메시지가 나오는 문제가 발생했다.


👀원인

	inputEmail
            .filter({ !$0.isEmpty })
            .debug()
            .drive(with: self) { owner, email in
                emailIsUsable.onNext(false)
                checkBtnActive.onNext(true)
                emailRequestable.onNext(owner.isValidEmail(email)) //유효성 검사를 통한 request가능 여부
            }
            .disposed(by: disposeBag)

텍스트 필드 emailTextField.rx.text.orEmpty의 형태로 inputEmail을 넘긴 다음 위와 같은 형태로 구현했다.

텍스트가 바뀌면 이메일 중복 확인에 대한 값을 false로 만들어 회원 가입 버튼 탭시, 이메일 중복 값에 대한 확인 해야하도록 만들었다.

 

 

하지만, 텍스트필드의 커서를 옮기는 과정에서도 이벤트가 발생하여 이메일 중복 확인에 대한 값을 false로 만들어 버려, 회원 가입 버튼을 탭했을때 이메일 중복 검사에 대한 값이 false가 나와 중복 확인을 하라고 나온 것이다.

 

  • 분석
  • textField.rx.text에 들어가 이벤트를 방출하는 코드를 타고 들어가다 보면 다음과 같은 함수가 나온다
    internal func controlPropertyWithDefaultEvents<T>(
        editingEvents: UIControl.Event = [.allEditingEvents, .valueChanged],
        getter: @escaping (Base) -> T,
        setter: @escaping (Base, T) -> Void
        ) -> ControlProperty<T> {
        return controlProperty(
            editingEvents: editingEvents,
            getter: getter,
            setter: setter
        )
    }
 

UIControl.Event | Apple Developer Documentation

Constants describing the types of events possible for controls.

developer.apple.com

공식 문서를 보면 allEditingEvents는 텍스트 필드의 모든 editing Touch 이벤트를 말하며, 그 안에는 editingDidEndOnExit이 포함된다.

그렇기 때문에 텍스트 필드의 입력이 종료되어 커서가 옮겨가는 도중에도 이벤트 방출이 되는 문제가 발생한다.


💡해결 아이디어

해결은 간단하다. 사실 텍스트 필드에서 퇴장하는 이벤트는 마지막으로 입력된 값과 같은 이벤트를 방출하기 때문에 distinctUntilChanged 오퍼레이터를 추가해주면 된다.

 

	inputEmail
            .filter({ !$0.isEmpty })
            .debug()
            .distinctUntilChanged()
            .drive(with: self) { owner, email in
                emailIsUsable.onNext(false)
                checkBtnActive.onNext(true)
                emailRequestable.onNext(owner.isValidEmail(email)) //유효성 검사를 통한 request가능 여부
            }
            .disposed(by: disposeBag)

 

근데 여기서 한가지 걱정이 들 수 있다.

"공식 문서에서는 이미 방출된 이벤트를 방출하지 않는다 라고 되어있는데, 그럼, 만약 사용자가 지웠다가 똑같은 값을 입력하면  똑같은 이벤트가 방출된 이력이 있으니까 이벤트 방출 안되는 문제가 발생하지 않을까? "

하지만 그런 이벤트는 발생하지 않는다.

Reactive X의 공식문서에 따르면 일부 구현에서는 바로 이전의 요소와만 비교하여 연속된 중복 값만을 필터하는 오퍼레이터가 있다고 되어있다.

Swift에서는 바로 그 경우에 해당되는 듯 하다

 


 🛠️해결