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

Stacking Fire

Tip. UITextField의 글자수 제한 본문

개발/iOS

Tip. UITextField의 글자수 제한

라우비 2017. 7. 9. 21:37

패스트캠퍼스에서 딜리게이트에 관련된 수업을 진행하던 도중, 텍스트필드의 글자수를 제한하는 것에 관련된 예제를 진행한 적이 있었습니다. 최초에 나온 답변에 대해서 다시 버그를 찾아내고, 그 버그를 픽스하고 하면서 Delegate에 대해서 알아볼 수 있는 굉장히 유익한 시간이었는데요. 해결하고자 하는 요건은 아래와 같았습니다.


  • 입력되는 글자수가 10자를 넘지 않을 것.
  • 입력시 커서가 텍스트 내에 어디에 있든 상관없이 작동할 것.
  • 복사해온 스트링을 넣어도 알아서 거부할 것.
  • 삭제도 문제없이 될 것.

단순히 잘 해결했다는 느낌을 떠나서, 딜리게이트의 구조를 정확히 알고 또 구현하고자 하는 상황의 의미를 그대로 코드로 자아낸 예제라서 기억에 많이 남습니다. 당시 배운 것들을 정리합니다.

풀이와 설명

  • 결론부터 말하면 답은 아래와 같습니다.

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        let newLength = (textField.text?.characters.count)! + string.characters.count - range.length
        return !(newLength > 10)
    }
  • UITextField에는 textField(_:shouldChangeCharactersIn:replacementString:)->Bool 이 부분이 아마 이렇게 되어있을 거에요.

    protocol UITextFieldDelegate {
        func textField(_ textField: UITextField,shouldChangeCharactersIn range: Range<String.CharacterView.Index>, replacementString string: String) -> Bool
    }
    
    class UITextField {
        var delegate: UITextFieldDelegate?
        var text: String = ""
        func keyTouched(in range: Range<String.CharacterView.Index>, replacementString string: String) {
            if (self.delegate?.textField(self, shouldChangeCharactersIn: range, replacementString: string))! {
                self.text = self.text.replacingCharacters(in: range, with: string)
            }
        }
    
    }
  • ViewController엔 이렇게 되어 있을 겁니다.

    class ViewController: UIViewController, UITextFieldDelegate {
    
        @IBOutlet weak var myTextField: UITextField!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            self.myTextField.delegate = self
        }
    
        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            let newLength = (textField.text?.characters.count)! + string.characters.count - range.length
            return !(newLength > 10)
        }
    }
  • shouldChange...이므로 결국 추가하거나 교체하는 것도 지원합니다. 즉 키보드던 뭐던 텍스트필드에 있는 텍스트에 변화를 가할 수 있는 모든 경우에 불리게 됩니다.

  • 추가될 값과 지워질 양, 수정을 행할 위치가 필요합니다. 각각 다음과 같은 값으로 전달됩니다.

    • 현재 커서 위치 : range.location
    • 지워질 양 : range.length
    • 추가될 값 : string
  • 상황별로 따져보기.

    1. 일반 키보드 누름
      • range.location = 현재 커서 위치
      • range.length = 0
      • string = 누른 키보드의 캐릭터
    2. 지우기(delete)누름
      • range.location = 현재 커서 위치 - 1 (문자열 처음에서는 안됨)
      • range.length = 1
      • string = ""
    3. 복사해서 붙여넣음
      • range.location = 현재 커서 위치
      • range.length = 0
      • string = 복사된 스트링
    4. 문자열을 선택한 후 붙여넣기 (바꿔넣기)
      • range.location = 현재 커서 위치
      • range.length = 선택된 스트링 길이
      • string = 복사된 스트링
  • 위와 같이 들어옵니다. 여기서 if문 안을 살펴봅시다.

    if (self.delegate?.textField(self, shouldChangeCharactersIn: range, replacementString: string))! {
        self.text = self.text.replacingCharacters(in: range, with: string)
        //1. 커서 위치(range.location)에서 (range.length)만큼 문자열을 지운다.
        //2. 커서 위치(range.location)에 추가할 문자열(string)을 추가한다.
    }
  • replacingCharacters함수가 실행되는 과정을 통해 문자열 변화가 일어난 후의 길이를 계산해 보겠습니다.

    //변화 후 텍스트 길이 = 현재 텍스트 길이 + 추가되는 텍스트 길이 - 지울 길이
    let newLength = (textField.text?.characters.count)! + string.characters.count - range.length
    return !(newLength > 10)


'개발 > iOS' 카테고리의 다른 글

Unit Test 사용법  (0) 2017.08.17
App과 View의 LifeCycle  (0) 2017.07.20
Tip. UIControl 바깥을 탭해서 키보드 내리기  (0) 2017.07.04
Tip. UINavigationBar의 사용  (0) 2017.07.04
Realm 모바일 데이터베이스  (0) 2017.07.02
Comments