iOS 개발자가 많이 하는 실수 - guard를 잘못 사용 (Early Exit Misuse)
Swift의 guard 문은 조건이 충족되지 않으면 즉시 함수 흐름을 종료하는 문법입니다.
그래서 return, break, continue, throw 중 하나가 반드시 필요하며, return을 빠뜨리는 문법적 오류는 애초에 발생할 수 없습니다.
그러나 초보 개발자는 다음과 같은 논리적 오류(Logical Bug)를 자주 겪습니다
1. 잘못된 이해: “guard를 쓰면 안전하다”
많은 초보자는 guard가 if let의 단순한 대체라고 생각합니다.
그러나 guard의 본질은:
조건이 안 맞으면 함수 실행을 중단한다(Early Exit)
즉, guard는 함수의 흐름을 분기시키기 때문에 잘못 쓰면 로직이 틀어짐.
2. 실무에서 자주 발생하는 잘못된 guard 사용 패턴
2-1. guard를 너무 “일찍” 사용해 로직이 실행되지 않는 문제
func load() {
guard isLoaded else { return } // ❌ isLoaded가 false면 항상 return
fetchRemoteData()
}
개발자의 의도:
- “로드됐으면 fetch 한다”
실제 동작:
- 로드되기 전에는 영원히 fetchRemoteData가 호출되지 않음
해결
조건의 의미를 다시 점검하고 올바른 위치에 guard 배치.
guard !isLoaded else { return } // 아직 안 불러왔다면 로드해야 함
fetchRemoteData()
2-2. guard 위치 때문에 함수의 중요한 로직이 실행되지 않는 문제
func configureUI() {
guard let data = viewModel.data else { return }
titleLabel.text = data.title
setupBindings() // ❌ data가 nil이면 절대 호출되지 않음
}
개발자는 “UI 구성을 모두 여기서 한다”고 생각하지만
실제로는 data가 nil일 때 UI 바인딩이 전혀 실행되지 않음.
해결
UI 흐름 자체가 data 존재 여부에 의존하는지 먼저 판단해야 함.
func configureUI() {
setupBindings() // 항상 실행되어야 하는 작업
guard let data = viewModel.data else {
titleLabel.text = "기본 제목"
return
}
titleLabel.text = data.title
}
2-3. guard 조건을 과도하게 묶어서 정상 사용자가 차단되는 문제
guard let user = currentUser else { return }
guard user.isLoggedIn else { return }
guard user.isAdmin else { return } // ❌ 관리자만 통과됨
showDashboard()
처음에는 “권한 체크” 정도로 작성했지만,
이제 일반 로그인 유저는 대시보드를 전혀 볼 수 없음.
해결
권한 체크 로직을 의미별로 분리하거나, 역할 기반 조건 분기 사용.
guard let user = currentUser else { return }
guard user.isLoggedIn else { return }
if user.isAdmin {
showAdminDashboard()
} else {
showUserDashboard()
}
2-4. guard return 타입을 잘못 이해한 경우 (Swift 초보 흔한 함정)
func submit() {
guard let text = textField.text else { return false } // ❌ 컴파일 오류
}
함수의 리턴 타입이 Void인데 guard에서 return false를 사용하려고 함.
해결 1 — 함수 타입에 맞게 수정
func submit() -> Bool {
guard let text = textField.text else { return false }
return true
}
해결 2 — Void 함수라면 단순 return 사용
func submit() {
guard let text = textField.text else { return }
// ...
}
2-5. guard를 남발하여 함수 가독성을 해치는 문제
guard condition1 else { return }
guard condition2 else { return }
guard condition3 else { return }
guard condition4 else { return }
guard condition5 else { return }
// 실제 로직은 여기부터
guard는 강력한 도구지만
연속으로 여러 번 쓰이면 오히려 흐름이 복잡해짐.
해결
- 조건을 구조화
- 하나의 guard에서 묶음 처리
- 또는 검증 전용 함수를 분리
예)
guard validateUser(), validateToken(), validateSession() else { return }
2-6. guard 아래에서 의미 없는 중복 체크
guard let name = user.name else { return }
// 아래에서 또 nil처럼 다룸 — 불필요한 패턴
if name.isEmpty { }
guard로 이미 nil이 아님을 보장했는데
또 Optional처럼 취급하는 잘못된 로직.
해결
- guard 이후에는 Optional이 아닌 확정 값으로 생각하고 코드를 작성
3. guard를 잘 쓰는 핵심 원칙 (실무 기준)
- guard는 반드시 “실패 처리”를 담당해야 한다.
- 정상 흐름 코드는 guard 아래로 “평평하게(flat)” 이어져야 한다.
- guard 위치를 잘못 잡으면 함수 전체의 의미가 달라진다.
- “이 조건이 실패하면 이 함수는 더 진행할 의미가 없다”라는 상황에서만 guard 사용.
- guard 조건이 두 개 이상이면 반드시 조건의 의미 단위로 그룹화해야 한다.
4. 정리
- guard는 return 누락 때문에 문제가 생기지 않는다 → 컴파일러가 막아줌
- 진짜 문제는 “잘못된 위치, 잘못된 논리, 과도한 조기 종료(Early Exit)”
- 예측하지 못한 시점에 함수가 멈춰 로직이 건너뛰어지는 실수가 가장 흔함
- guard는 강력한 논리 도구이므로,
“이곳에서 조기 종료가 발생하는 것이 정말 맞는가?”를 항상 고민해야 함
'Dev Study > iOS' 카테고리의 다른 글
| iOS 개발자가 많이 하는 실수 - Dictionary에서 key 존재 여부 확인 없이 강제 언래핑(!) (0) | 2025.12.04 |
|---|---|
| iOS 개발자가 많이 하는 실수 - struct vs class 차이를 오해하여 발생하는 문제 (Value Type / Reference Type 혼동) (1) | 2025.12.04 |
| iOS 개발자가 많이 하는 실수 - Array append 반복 사용 vs reserveCapacity / Array(repeating:count:) 성능 문제 (0) | 2025.12.04 |
| iOS 개발자가 많이 하는 실수 - 문자열 비교 시 lowercased() 반복 사용 문제 (0) | 2025.12.04 |
| iOS 개발자가 많이 하는 실수 - Optional Binding 중첩(if let 지옥) (0) | 2025.12.04 |
| iOS 개발자가 많이 하는 실수 - 옵셔널을 강제 언래핑(!)하기 (0) | 2025.12.04 |
| iOS 색상 토큰(Role-based Color Tokens) 역할 설명 가이드 (0) | 2025.12.04 |
| TCA(The Composable Architecture) 사용 가이드(v1.23.1) (1) | 2025.11.18 |

