iOS 개발자가 많이 하는 실수 - Auto Layout 제약 조건 충돌 경고를 무시하고 방치하는 실수
Xcode 디버그 콘솔에 다음과 같은 로그가 보인 적이 있을 것입니다.
[LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
...
많은 초보자(그리고 바쁜 실무자들도)는 이 경고를 한 번 보고 말합니다.
“일단 화면은 대충 나오니까… 나중에 보자.”
그러나 Auto Layout 제약 조건 충돌은:
- 특정 기기/회전/다크모드/동적 폰트 환경에서
- 레이아웃 무너짐, 겹침, 잘림, 튀는 현상 등으로 이어지며
장기적으로는 유지보수 악몽을 만듭니다.
1. Auto Layout 경고의 의미
대표적인 로그 형태:
[LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
(
"<NSLayoutConstraint:0x6000021a7b40 UILabel:0x7fcd0840.leading == 16 (active)>",
"<NSLayoutConstraint:0x6000021a7c10 UILabel:0x7fcd0840.leading == 24 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x6000021a7c10 UILabel:0x7fcd0840.leading == 24 (active)>
해석:
- 시스템이 동시에 만족시킬 수 없는 두 개 이상의 제약 조건을 발견했음
- 그래서 임의로 하나를 깨뜨리고 레이아웃을 맞추려고 시도함
- 어떤 제약이 깨졌는지까지 로그에 표시됨
당장은 화면이 “대충 맞게” 나올 수 있지만
앞으로 다른 상황(화면 크기, 언어, 컨텐츠 길이)이 되면
완전히 다른 모습으로 깨질 수 있습니다.
2. 왜 무시하면 안 되는가?
- 기기/환경에 따라 다르게 깨짐
- iPhone 15 Pro에서는 괜찮아도 SE에서 깨질 수 있음
- 다국어(특히 긴 독일어/프랑스어/한글 문자열)에서 텍스트가 잘림
- Dynamic Type(접근성 폰트 크기) 활성화 시 UI가 붕괴
- 레이아웃 수정 시 디버깅 난이도 폭발
- 시간이 지나 다른 개발자가 해당 화면을 수정하려고 할 때
- 이미 존재하던 constraint conflict 때문에 원인 파악이 어려워짐
- 시스템이 임의로 constraint를 깨기 때문에 예측 불가능
- Auto Layout이 어느 제약을 포기할지는 항상 개발자의 의도와 같지 않음
- 일부 환경에서만 특정 제약이 깨져서 “유령 버그”로 나타남
3. 대표적인 원인 패턴
3-1. 같은 축에 대해 중복된 제약
예:
label.leading == 16
label.leading == 24
Interface Builder에서 constraint를 여러 번 추가했거나
코드로 중복 추가한 경우 발생.
3-2. Hugging/Compression Priority 설정 부재
두 개의 뷰가 서로 공간을 놓고 싸우는 상황:
- 두 label이 나란히 있을 때
- “누가 줄어들고, 누가 유지될 것인지” 우선순위가 필요
이를 설정해주지 않으면 Auto Layout이
어떤 걸 줄여야 할지 결정하지 못하고 conflict를 일으키기도 합니다.
3-3. Intrinsic Content Size와 상충되는 고정 제약
예:
- UILabel에 height == 20 고정
- 동시에 상/하 anchor를 superview에 붙임
내용/폰트 등으로 intrinsic height가 24가 되어야 하지만,
20 고정 제약과 상충할 수 있습니다.
3-4. ScrollView + Content Layout 문제
ScrollView 안에 들어가는 content view의:
- width/height 제약
- contentLayoutGuide, frameLayoutGuide 사용 실수
때문에 “ambiguous content size” 또는 constraint conflict가 자주 발생합니다.
4. 해결 방법: 로그를 읽고, 의도된 레이아웃을 명확히 하기
4-1. 로그에서 “깨진 제약” 찾기
경고 로그 마지막 부분에는 보통 이렇게 나옵니다.
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x6000021a7c10 UILabel:0x7fcd0840.leading == 24 (active)>
이 제약 조건이 Auto Layout에 의해 깨졌다는 의미입니다.
해당 constraint를 만든 위치를 찾는 방법:
- IB에서 Constraint 선택 → Identifier 지정
- 코드에서 constraint 생성 시 식별 가능한 변수/identifier 사용
4-2. 우선순위(Priority) 조정
동시에 만족할 수 없는 조건이라면,
어느 쪽이 더 중요한지를 시스템에 알려줘야 합니다.
예:
label.setContentCompressionResistancePriority(.required, for: .horizontal)
label.setContentHuggingPriority(.required, for: .horizontal)
또는 제약 정의 시:
constraint.priority = .defaultLow
이렇게 하면:
- 충돌 시 우선순위가 낮은 제약이 깨지도록 유도
- 개발자 의도에 맞게 레이아웃이 조정됨
4-3. 불필요한 중복 제약 제거
스토리보드/IB에서 constraint를 여러 번 추가했다면:
- Size Inspector에서 중복 제약을 찾아 제거
- “leading + centerX”처럼 서로 충돌하는 제약이 없는지 확인
4-4. Content Compression / Hugging 이해하기
핵심 개념:
- Compression Resistance: 얼마나 줄어들기 싫어하는가
- Content Hugging: 얼마나 늘어나기 싫어하는가
두 label이 나란히 있을 때:
- 왼쪽 label의 Compression Resistance를 높이면
오른쪽 label이 먼저 줄어든다.
예:
leftLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
rightLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
5. 실무에서 자주 쓰는 디버깅 팁
5-1. Xcode Debug View Hierarchy 활용
Xcode에서
- Debug Navigator → “Debug View Hierarchy” 클릭
→ 실제 뷰 계층과 constraint를 3D로 볼 수 있고
어떤 뷰가 어디에 위치하는지 직관적으로 확인 가능.
5-2. UIView.alertForUnsatisfiableConstraintsoverride (디버그용)
디버그 빌드에서만 특정 뷰가 constraint conflict를 일으킬 때 breakpoint를 걸 수도 있습니다.
(실제 앱 코드에 상시 넣어두기보다는
디버깅 세션에서 일시적으로 사용하는 편이 좋습니다.)
6. “일단 보이니까 됐다”는 생각의 대가
Auto Layout 경고를 무시하면 시간이 지날수록:
- 새로운 화면/기기/언어가 추가될 때마다 예상 못 한 레이아웃 깨짐 발생
- 팀원들이 “이 화면 손대기 싫어하는” 상태가 됨
- 나중에 전체 레이아웃을 갈아엎는 일이 생김
특히 iPad 멀티 윈도우, Dynamic Type, 다국어, RTL(우-to-좌 언어) 등을 고려하는 앱에서는
이 문제를 방치할수록 복구 비용이 폭증합니다.
7. 실무용 체크리스트
- Xcode 콘솔에 Unable to simultaneously satisfy constraints가 보이는가?
- 보인다면 반드시 원인을 파악할 것.
- 깨진 constraint가 무엇인지 로그에서 확인했는가?
- 의도한 레이아웃에서 어떤 제약이 더 중요하고, 어떤 제약은 포기해도 되는지 정했는가?
- Hugging / Compression Resistance Priority를 올바르게 설정했는가?
- ScrollView + Auto Layout 구조에서 content size 제약을 명확히 했는가?
8. 요약
- Auto Layout 제약 충돌 경고는 “그냥 무시해도 되는 로그”가 아니라,
향후 레이아웃 버그를 예고하는 경고등이다. - 로그를 통해 어떤 제약이 충돌하는지 분석하고,
우선순위/중복 제약/잘못된 anchor 설정을 반드시 수정해야 한다. - 초기에 조금 귀찮더라도, 경고를 없애두는 것이
장기적인 유지보수 비용을 크게 줄인다.
핵심 문장:
Auto Layout 경고는 언젠가 실제 버그로 돌아온다.
보이는 지금, 잡아두는 게 가장 싸게 먹힌다.

