[iOS] textField(_:shouldChangeCharactersIn:replacementString:)

Logan·2021년 3월 25일
1
optional func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, 
replacementString string: String) -> Bool

이 method는 두번째 파라미터 range를 통해 추가되거나 삭제할 범위를 전달하고,
세번째 파라미터 string으로 현재 입력받은 문자열을 전달합니다.
그리고 return값이 true여야 실제로 textField에 입력할 수 있습니다.
만약 이 method 안에서 텍스트필드에 입력된 최종 텍스트를 가져오려면,
아직 true 값을 return을 하기 전 이기 때문에,

위의 파라미터들과 NSString을 조합해야 텍스트필드에 입력된 최종 텍스트를 가져올 수 있습니다.

  1. textField.text를 NSString 타입으로 변경한다.
  2. replacingCharacters(in: range, with: string) 두번째, 세번째 파라미터를 각각 이 method에 전달해준다.
extension ViewController: UITextFieldDelegate {
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        let input = NSString(string: textField.text ?? "")
        let output = input.replacingCharacters(in: range, with: string)

        print("printed:", input, output)

        return true
    }
}

// printed:     1
// printed: 1   12
// printed: 12  123
// printed: 123 1234

위에서 언급한 것처럼, input(textField.text)에 저장된 값은 아직 return 하기 전이기 때문에 출력되지 않습니다.

그래서 replacingCharacters(in: range, with: string)으로 현재 추가되거나 삭제할 범위를 골라서 현재 추가한 String으로 바꿔줍니다.

참고로 텍스트를 지울 경우 string엔 빈 문자열 ""이 전달됩니다.

반대로 최종 문자열을 구현할 때 String이 제공하는 method를 사용한다면, NSRange를 Range로 바꿔줘야하기 때문에 구현이 복잡해 질 수 있습니다. 그래서 testField.text를 NSString 타입으로 변경하는 방법을 사용하는게 편합니다.

extension ViewController: UITextFieldDelegate {
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        let input = textField.text ?? ""
        if let myRange = Range(range, in: input) {
            if let output = textField.text?.replacingCharacters(in: myRange, with: string) {

                print("printed:", input, output)
            }
        }
        return true
    }
}

// printed:     1
// printed: 1   12
// printed: 12  123
// printed: 123 1234

여러 사람들이 '불편하다' 라고 해서 불편합니다. 라고 얼렁뚱땅 넘어가려고 했지만, 확인을 해봤습니다.

NSRange를 Range 타입으로 바꾸고 method를 사용하는 부분에서는 큰 차이는 없지만, optional 타입으로 인스턴스들이 생성됩니다.

옵셔널 바인딩을 통해 사용해주어야 하기 때문에 String을 NSString으로 바꿔서 사용하는게 더 간결합니다.

RxSwift로 바꾸면 훨씬 간결합니다. 😅

profile
iOS개발자 꿈나무

0개의 댓글