글자 수 제한을 걸어야 하는 경우가 생긴다.
나의 경우 collectionView에 두 개의 TextField가 있고 첫 번째 것은 이름, 두 번째 것은 나이를 입력받는다.
stackoverflow에서 힌트를 얻어 다음과 같이 코드를 작성하였는데 한글/영어 모두 잘 작동된다.
한 번에 여러 글자를 복사해서 붙여 넣는 경우 마지막 글자를 지우는게 아니어서 약간의 버그가 있긴 하지만 큰 문제가 될 것 같진 않다.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
guard let text = textField.text else { return true }
let newLength = text.characters.count + string.characters.count - range.length
debugPrint("newLength = \(newLength)")
if newLength > 10 {
// label에 경고 문구를 띄운다.
let cell = self.collectionView.cellForItemAtIndexPath(NSIndexPath(forRow: 1, inSection: currentSection!)) as! SettingsCell
cell.cellLabel.text = "\((cell.cellLabel.text)!)\n(이름은 10글자를 넘으면 안되요~)"
for _ in 0 ..< newLength - 10 {
textField.deleteBackward()
}
}
return true
}
처음에 이렇게 작성하였으나 더 좋은 소스를 발견하여 아래와 같이 수정하였다. 물론 위의 버그도 해결하였다.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let currentText = textField.text ?? ""
let prospectiveText = (currentText as NSString).stringByReplacingCharactersInRange(range, withString: string)
switch currentSection! {
case 0:
// name
let length = prospectiveText.characters.count
if length > 10 {
// label에 경고 문구를 띄운다.
let cell = self.collectionView.cellForItemAtIndexPath(NSIndexPath(forRow: 1, inSection: currentSection!)) as! SettingsCell
cell.cellLabel.text = "\((cell.cellLabel.text)!)\n(이름은 10글자를 넘으면 안되요~)"
}
return prospectiveText.characters.count <= 10
case 1:
// age
if !prospectiveText.containsOnlyCharactersIn("0123456789") {
// label에 경고 문구를 띄운다.
let cell = self.collectionView.cellForItemAtIndexPath(NSIndexPath(forRow: 1, inSection: currentSection!)) as! SettingsCell
cell.cellLabel.text = "\((cell.cellLabel.text)!)\n(나이는 숫자만 적어주세요~)"
}
return prospectiveText.containsOnlyCharactersIn("0123456789") && prospectiveText.characters.count <= 3
default:
return true
}
}
이 소스에는 String extension을 사용하는데 extension source는 아래 링크에서 확인할 수 있다.
물론 이 source가 위 코드의 원천이다.
한편, 다른 기능도 구현해보고 싶다.
예컨대 사용자가 키입력 때마다 실시간 조회를 해 보거나 할 때 사용해보려 한다.
오토마타라고 하는 것 같은데..
한글 입력 판단이 생각보다 간단하지가 않다. 어딘가 오픈소스로 나와있을 것 같은데..
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
debugPrint("\(textField.text) \(string) \(range)")
return true
}
이렇게 키 입력을 찍어 보면 아래와 같이 나온다.
"Optional(\"\") T (0,0)"
"Optional(\"T\") y (1,0)"
"Optional(\"Ty\") Typical (0,2)"
"Optional(\"Typical\") (7,0)"
"Optional(\"Typical \") ㅇ (8,0)"
"Optional(\"Typical ㅇ\") ㅖ (9,0)"
"Optional(\"Typical 예\") ㅅ (9,0)"
"Optional(\"Typical 옛\") ㅗ (9,0)"
"Optional(\"Typical 예소\") ㅇ (10,0)"
"Optional(\"Typical 예송\") f (8,0)"
"Optional(\"Typical f예송\") u (9,0)"
아래는 결과 화면..