Roen의 iOS 개발로그

UITextField에서 입력 값을 제한해보자

by Steady On

iOS

앞의 포스팅과 이어지는 부분이 있기 때문에 보고 오시면 좋을 것 같습니다!

2023.09.03 - [iOS] - UITextField에 입력도, 붙여넣기도 막아버리기

 

UITextField에 입력도, 붙여넣기도 막아버리기

서론 UITextField는 사용자에게서 입력을 받을 때 많이 사용합니다. inputView 메서드를 통해서 UIPicker와 결합해서 쓰는 경우도 많고요. 이럴 때 우리가 입력 받아야 하는 건 "숫자만!", "8자 까지만!" 등

steady-on.tistory.com

 

 

서론

앞의 포스팅에서는 UITextField의 붙여넣기와 입력을 막아봤는데요. 입력을 단순히 막는게 아니라 숫자로만, 혹은 길이를 제한해야 할때는 어떡해야 할까요? 입력을 막기위해서 키보드 타입을 변경해도 외부 키보드로 넣는 입력 값은 또 막을 수가 없기 때문에 이건 꼭 막아줘야 할거에요.

 

textField(\_:shouldChangeCharactersIn:replacementString:)

앞의 포스팅에서 다뤘던 그 친구!! 한번 더 소환해 보겠습니다!

이 메서드에 대해서 간단히 요약하자면, 매개변수로 받는 range는 값이 바뀌기 시작한 첫번째 인덱스를 가리키고, string은 textField에 새로 추가된 입력 값이 온다고 했어요. 그리고 true를 반환하면 값의 변경, 그러니까 새로 들어온 입력값을 반영하고, false는 반영하지 않겠다는 의미라고 했고요.

 

그럼 입력 값을 숫자로만, 혹은 알파벳으로만 제한하고 싶으면 어떡해야 할까요?

 

string 매개변수 이용하기

string 매개변수에는 사용자가 입력한 값이 들어오는데요. 한글자 한글자 입력한다면 한글자씩 들어올거고, 붙여넣기로 덩어리를 넣는다면 그 덩어리가 들어올거에요. 그리고 우린 이 매개변수로 들어오는 값을 통해서 입력을 제한해 줄 수 있어요.

예를 들어, 위 화면에서 TextField에는 숫자만 들어가야 한다고 가정해볼까요? 그럼 뭐 일단

ViewController에서 UITextFieldDelegate도 채택하고, textField의 delegate도 self로 잘 할당을 하면 준비는 끝날거에요. 그리고 다음과 같이 메서드를 작성해 줄 수 있는데요.

extension MainViewController: UITextFieldDelegate {
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        guard Int(string) != nil else { return false }
        return true
    }
}

string을 Int로 형변환이 되면 변경을 받아들이고(return true), 변환이 안되면 변경을 받아들이지 않겠다(return false)는 겁니다. 여기까진 참 쉽죠? 다들 여기까진 뭐 제코드를 보시지 않아도 쉽게 오셨을거에요. 근데 한가지 문제가 있어요;;; 이렇게 해버리는 경우 BackSpace까지 막혀서 글자가 안지워진다는 겁니다...ㅎㅎ

왜냐면, 사용자가 하는 모든 입력은 string으로 들어온다고 했잖아요. 근데 BackSpace도 하나의 입력값이 되어서 Int로 형변환을 해봤는데 안되니까 무시되어버리거든요;;;;

백스페이스가 안먹혀서 글자가 안지워짐...

사용자가 입력을 잘못한걸 인지하고 수정하고 싶어도 수정할 수 없는 상황이 되어 버렸습니다..... 그럼 이걸 또 디버깅을 해야죠? 입력값이 숫자인지 판단하기전에 BackSpace입력을 먼저 판단하고 적용해주면 될거 같아요.

 

BackSpace 예외 적용하기

입력값이 BackSpace인지 확인하는 방법은 사실 조금 까다로웠는데요. 안까다롭습니다;;; 원래는 C언어의 cString으로 변환을 한다음에 이게 BackSpace가 맞냐 값이 이거나 확인 해야 했었거든요?

if let char = string.cString(using: .utf8),
    strcmp(char, "\\b") == -92 {
    return true
}

(C를 몰라서 대충 맥락만 이해하고 -92가 대체 어디서 나온건지는 아무리 읽어봐도 모르겠는 사람.... 그거 저에요 ㅠㅠ)

 

근데 사실 엄청 간단한 방법이 있습니다!

 

print 찍히는거 보이시나요? BackSpace를 입력할때는 ""(빈문자열)이 입력되고 있습니당! 근데 우리가 일반적으로 빈문자열을 입력할 수가 없죠? 스페이스바만 눌러도 그건 빈문자열이 아니니깐요! 그래서 이걸 통해서 디버깅을 해보면 요런 코드를 만들 수 있게 됩니다.

extension MainViewController: UITextFieldDelegate {
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        
        guard string.isEmpty || Int(string) != nil else { return false }
        
        return true
    }
}

string이 비어있거나 숫자로 형변환이 가능하면 입력을 반영하고, 아니면 안하고! 요렇게 해주면, 문제없이 잘 지워지는 것을 볼 수가 있습니다!

 

그럼 텍스트의 일정 길이 이상에서는 입력을 막으려면?

이쯤되면 갑자기 "엇? 근데 매개변수로 들어오는건 사용자가 방금 입력한 값이라면서요! 그걸로 길이를 어떻게 알아요;;;" 하실 수도 있을 것 같아요. 근데 잘 볼것도 없이 첫번째 매개변수를 활용하면 됩니다!! 첫번째 매개변수에는 지금 입력 값이 들어오고 있는 textField 그 자체가 들어오게 되는데요. 이 매개변수의 text 프로퍼티를 가져오면 지금 textField에 입력되어 있는 값을 알 수 있겠죠?  예를 들어 3자리 넘어서는 입력이 더이상 안되게 해본다고 할까요?

extension MainViewController: UITextFieldDelegate {
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    	// text의 길이가 3을 초과하면 입력 불가
        guard let text = textField.text, text.count < 3 else { return false }
        // BackSpace와 숫자인 경우에만 허용
        guard string.isEmpty || Int(string) != nil else { return false }
        
        return true
    }
}

이런 식으로 textFeild 매개변수를 이용하면 아주 간단하게 길이에 대한 제한도 적용할 수 있게 됩니다!

 

마무리

TextField에 입력을 막는 것에 이어서 TextField에 입력을 제한 하는 것까지 알아봤습니다! 이정도면 엥간한 입력관련 UI는 다 대응가능 하지 않을까 싶습니다!! ㅎㅎ(아님말고! 책임없는 쾌락)

그럼 다음엔 또 뭘 삽질하다가 오게 될까여? 저도 궁금하네요 ㅎㅎ

다음 포스팅에서 만나요~~

블로그의 정보

Roen의 iOS 개발로그

Steady On

활동하기