![[Ting] 유저피드백 / Textfield 공백검증, 특수문자 검증 구현, 키보드 내리는 기능 구현](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcLFE4%2FbtsMraVxbCm%2FuWhhLKESRuTBmhk1zjVGMK%2Fimg.png)


유저피드백을 받았다.
1. 닉네임 이외에 다른 필드에서 공백 한번으로 비어있는 정보 생성 가능
2. 특정 필드의 정보만 변경하고 싶은데, 한번 클릭하면 마지막 필드까지 내려갈때까지 키보드를 내릴 수 없음.
위 두가지 사항을 피드백 받았다.
수정해야할 부분이다. 닉네임 중복검증 및 공백, 특수문자 검증에만 신경 쓴 나머지 다른 부분들을 체크하지 못했다.
키보드도 마찬가지. 텍스트필드간의 이동 및 작성 완료시 키보드가 내려가는것에만 집중한 나머지 한가지 필드만 수정할지도 모르는 케이스를 간과하고 말았다.
수정해보자.
먼저 텍스트필드에 예외처리를 해보자
다른 파일에서도 코드를 재사용할 수 있도록, 별도의 파일로 분리를 해두었다.
import UIKit
// MARK: - 공백, 줄바꿈으로만 입력되었는지 체크
func isThereSpaces(text: String) -> Bool { // 어느곳이던 공백이 포함되어있으면 true return
return text.range(of: "\\s", options: .regularExpression) != nil
}
// MARK: - 특수문자 입력되었는지 체크
func isThereSpecialChar(text: String) -> Bool { // 어느곳이던 특수문자가 포함되어있으면 true return
return text.range(of: "[^a-zA-Z0-9가-힣]", options: .regularExpression) != nil
}
첫번째 코드는 공백, 줄바꿈을 체크하는 로직이다.
두번째코드는 특수문자를 검증하는 로직이다. 두 코드 모두 정규식을 사용하여 구현하였다.
자세한 내용은 아래의 글을 참고하자.
[Ting] TextField 공백, 특수문자 검사 로직 구현
닉네임 같은 값은 중복되지 않고, 유효한 Unique값으로 구현되는 것이 중요하다.Unique값으로 갈지, 태그를 붙여서 중복 닉네임을 허용할지는 각자 선택할 문제지만, Ting에서는 Unique값으로 결정.또
quaker.tistory.com
다만 다른 필드는 공백이나 콤마같은 특수문자가 들어가는 경우가 있어서 고민을 해봤는데,
결국 빈 정보를 만드는, 첫문자를 공백으로, 스페이스바 한번만 누르면 빈 내용이 생성이 된다.
이것을 막기위해, 첫문자가 공백인지 아닌지만 검증하기로 결정.
// MARK: - 첫 글자가 공백인지 체크
func isFirstCharSpace(text: String) -> Bool {
return text.first == " "
}
text.first 문자열의 첫 글자를 가져옴. " ".
즉 공백과 같은지 물었기 때문에, 공백이라면 true, 공백이 아니라면 false Return.
// 텍스트 필드 배열 생성
let textFieldList: [UITextField] = [
roleField.textField,
techStackField.textField,
toolField.textField,
workStyleField.textField,
interestField.textField
]
// 첫글자 공백 검사
for checkSpace in textFieldList {
let text = checkSpace.text ?? ""
// 첫글자 공백검사
if isFirstCharSpace(text: text) == true {
self.basicAlert(title: "오류", message: "첫 글자를 공백으로 작성할 수 없습니다.")
return
}
}
텍스트필드들을 배열에 담아서 배열을 생성하고, for문을 사용해 모든 텍스트필드의 공백을 검사한다.
코드상의 basicAlert은 기본적인 Alert형태를 코드 한줄로 바로 작성할 수 있도록 Extension으로 구현해놓고 사용했다.
따라서 저 코드가 alert을 생성하는 기본형태의 코드가 아니니 오해하지 말것.
저 자리에 공백이 있을때 실행되기를 원하는 코드를 작성하면 된다.
아예 코드를 작성하지 않아서 공백도 아닌 빈칸일때는,
// userInfo 객체 생성
let updatedUserInfo = UserInfo(
userId: userId,
nickName: nickNameField.textField.text ?? "",
role: roleField.textField.text ?? "",
techStack: techStackField.textField.text ?? "",
tool: toolField.textField.text ?? "",
workStyle: workStyleField.textField.text ?? "",
interest: interestField.textField.text ?? ""
)
// textField가 다 채워졌는지 확인하기 위해 배열에 저장
let isUpdateInfoEmpty = [
updatedUserInfo.nickName,
updatedUserInfo.role,
updatedUserInfo.techStack,
updatedUserInfo.tool,
updatedUserInfo.workStyle,
updatedUserInfo.interest
]
이런식으로 객체를 생성하고 배열에 저장해서,
if isUpdateInfoEmpty.allSatisfy({ !$0.isEmpty }) {
--- 중략 ---
} else {
basicAlert(title: "오류", message: "빈칸 없이 입력해주세요.")
}
이런식으로 allSatisfy와 isEmpty를 사용해서, 비어있는지 아닌지 검증한다.
공백검증 구현 완료.
이제 텍스트 필드가 아닌 다른 공간을 터치했을 떄, 키보드를 내려보자.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
super.touchesBegan(touches, with: event)
}
원래 이런식으로 구현했었는데, 카드뷰 밖의 영역, 베이지색 영역을 터치했을 때만 키보드가 내려가는 상황이었다.
하지만 카드뷰가 뷰의 대부분을 차지하고 있으므로,
// 다른 공간 터치시 키보드 사라짐
private func keyboardDown() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(keyboardDownAction))
tapGesture.cancelsTouchesInView = false // 다른 터치 이벤트도 전달되도록 설정
view.addGestureRecognizer(tapGesture)
}
@objc private func keyboardDownAction() {
view.endEditing(true)
}
전체 화면의 터치를 감지하도록 UITapGestureRecognizer를 사용했다.
그래서 addTarget과 비슷한 원리로, 클릭되었을때 어떤 기능을 동작하게 할지 별도의 함수로 또 작성하면 된다.
개선한 코드의 장점으로는
1. 보다 직관적인 방법
→ touchesBegan(_:with:)을 오버라이드하는 방식보다 뷰에 특정 제스처를 추가하는 것이 가독성이 높고 유지보수가 용이함.
2. 다른 UI 요소와 함께 사용 가능
→ cancelsTouchesInView = false 덕분에 버튼이나 스크롤뷰 등의 터치 이벤트도 정상 동작하면서 키보드만 내려가도록 설정 가능함.
3. 뷰 컨트롤러 간 일관성 유지 가능
→ keyboardDown()을 각 뷰 컨트롤러의 viewDidLoad()에서 호출하면 쉽게 적용 가능함.
키보드 내리기 개선 끝.
유저피드백 반영 완료.
살아남는 iOS 개발자가 되기 위해 끊임없이 노력하고 있습니다.