회원가입 화면을 UIKit + MVVM 구조로 구현하던 중, 모든 입력이 유효함에도 회원가입 버튼이 비활성화되어 있는 문제가 발생했습니다.
이 글에서는 그 문제의 원인을 분석하고 해결한 과정을 기록합니다.
문제 상황
회원가입 화면에서 다음 조건을 모두 만족했음에도 불구하고,
- 닉네임 / 이메일 중복 확인 완료
- 필수 약관 동의 체크 완료
- 비밀번호, 비밀번호 확인 입력 완료 및 일치
회원가입 버튼이 활성화되지 않고 비활성화 상태로 유지되는 문제가 발생했습니다.
원인 분석
MVVM 구조로 구현된 프로젝트에서 ViewModel은 사용자 입력 상태를 바탕으로 isFormValid 값을 계산하고, 클로저를 통해 View에 전달하고 있었습니다.
viewModel.isFormValidChanged = { [weak self] isValid in
self?.signupView.signupButton.isEnabled = isValid
self?.signupView.signupButton.backgroundColor = isValid ? .brand : .lightGray
}
하지만 실제로 View에서 버튼 상태는 바뀌지 않았습니다. 그 이유는 다음과 같습니다.
원인 1. validateForm() 호출 누락
View 내부에서 버튼 활성화 여부를 판단하는 validateForm() 함수가 존재하지만, 다음과 같은 사용자 액션 시 해당 함수가 호출되지 않았습니다.
- 중복 확인 버튼 클릭
- 약관 체크 상태 변경
- 도메인 직접 입력 전환
이로 인해 ViewModel에서 유효성을 판단하고 true를 전달했더라도, View에서는 버튼 상태가 갱신되지 않았습니다.
@objc private func textFieldDidChange() {
// 문제: 유효성 검사 누락
onInputChanged?(
usernameTextField.text ?? "",
fullEmail ?? "",
passwordTextField.text ?? "",
passwordConfirmTextField.text ?? "",
termsRequiredView.isChecked
)
}
termsRequiredView.checkChangedHandler = { [weak self] _ in
// 문제: 체크 변경 시 아무 로직도 실행하지 않음
}
해결 방법
- validateForm()을 View 내부의 모든 사용자 입력 변화 시점에 호출하도록 수정했습니다.
- 약관 체크 변경, 중복 확인 버튼 클릭 등 다양한 액션에서 유효성 재검사를 수행하도록 반영했습니다.
수정된 코드
@objc private func textFieldDidChange() {
validateForm() // 유효성 재검사
onInputChanged?(
usernameTextField.text ?? "",
fullEmail ?? "",
passwordTextField.text ?? "",
passwordConfirmTextField.text ?? "",
termsRequiredView.isChecked
)
}
termsRequiredView.checkChangedHandler = { [weak self] _ in
self?.validateForm()
}
validateForm() 구현
private func validateForm() {
let isUsernameValid = !(usernameTextField.text?.isEmpty ?? true)
let isEmailValid = fullEmail != nil
let isPasswordValid = isValidPassword(passwordTextField.text)
let isPasswordConfirmed = passwordTextField.text == passwordConfirmTextField.text
let isTermsAgreed = termsRequiredView.isChecked
let isFormValid = isUsernameValid && isEmailValid && isPasswordValid && isPasswordConfirmed && isTermsAgreed
signupButton.isEnabled = isFormValid
signupButton.backgroundColor = isFormValid ? .brand : .lightGray
}
마무리
회원가입 UI와 기능을 View에 구현하면서 MVVM으로 로직을 나누다 보니, 전체 코드가 약 700줄에 달하게 되었고 그 과정에서 기능이 중복되거나 가독성이 떨어지는 문제를 여러 차례 겪었습니다. 구조적으로 나누었다고 해도, 실제 구현에서는 여전히 View 내부의 상태 관리가 많은 부분을 차지하며 세심한 조율이 필요하다는 것을 느꼈습니다.
특히 사용자 액션이 ViewModel의 상태와 UI의 버튼 활성화 같은 UI 반응에 직접 영향을 미치기 때문에, 유효성 검사와 UI 갱신 로직이 명확하게 연결되어 있어야 안정적인 사용자 경험을 제공할 수 있다는 점을 실감했습니다.
이번 경험을 통해 "조건이 바뀌는 모든 순간마다 UI 상태를 다시 확인하고, 갱신하는 로직을 명시적으로 호출하는 것"이 얼마나 중요한지 다시 한 번 깨닫게 되었고, 앞으로의 화면 구성에서도 이를 자연스럽게 녹여낼 수 있을 것 같습니다.
'iOS > UIKit' 카테고리의 다른 글
[ UIKit ] UITableViewCell에서 AutoLayout 충돌 이슈 해결 (0) | 2025.04.16 |
---|---|
[UIKit] ViewController의 개념과 생명주기 정리 (0) | 2025.04.14 |
[ UIKit ] SwiftUI만 공부하던 내가 UIKit MVVM에서 클로저를 처음 마주쳤을 때 (0) | 2025.04.09 |
[ UIKit ] Combine으로 상태를 바인딩하는 방법 (0) | 2025.04.06 |
[ UIKit ] Delegate 패턴 알아보기 (0) | 2025.04.06 |