Life Logs && *Timeline

  • AutoLayout 충돌

    iOS 앱 개발 중 UI가 간헐적으로 보이지 않는 현상은 많은 개발자들이 경험하는 문제다. 특히 UIButton이나 UILabel, UIImageView처럼 명확히 코드로 추가된 뷰가 렌더링되지 않거나 화면에 보이지 않는 경우, 대체로 이유는 단순하지 않다. 이번 글에서는 UIKit 기반 프로젝트에서 UIButton이 간헐적으로 보이지 않는 대표적 사례를 바탕으로 원인과 해결 전략을 분석한다.


    증상 요약: UIButton이 보이지 않는 상황

    UIButton은 .system 타입으로 생성되며, 뷰 계층에도 명확히 추가되었고, 설정된 텍스트 및 액션도 정상적으로 등록되어 있다. 하지만 일부 기기나 특정 실행 시점에서 버튼이 화면에 렌더링되지 않는다.

    이러한 현상은 다음과 같은 로그와 함께 나타나는 경우가 많다:

    Unable to simultaneously satisfy constraints.
    Will attempt to recover by breaking constraint ...
    

    이와 같은 로그는 UIKit의 Auto Layout 엔진이 제약 조건 충돌을 감지하고 시스템이 임의의 제약을 제거하면서 레이아웃이 의도하지 않게 변형되는 상황임을 알려준다.


    원인 분석: AutoLayout Constraint 충돌

    문제를 일으킨 뷰 계층은 다음과 같이 구성되어 있었다:

    • stackView: 주요 콘텐츠를 수직 스택으로 정렬
    • footerBar: 하단의 버튼을 포함한 뷰
    • buttonsBar: import 버튼이 포함된 컨테이너

    문제는 stackView.bottomAnchorfooterBar.topAnchor 사이의 명확한 관계가 없거나 모순된 제약이 있을 경우 발생했다. UIKit은 스택뷰 내부와 외부 간 제약 조건을 맞추기 위해 자동으로 alignment 관련 제약을 생성하고, 이로 인해 충돌이 발생할 수 있다.

    또한, UIButtonCAGradientLayer를 적용할 경우, 버튼의 frame.zero 상태일 때 gradient가 제대로 표시되지 않아 버튼 자체가 보이지 않는 것처럼 착시를 일으킬 수도 있다.


    해결 방법: 안정적인 레이아웃 구성

    1. 명시적 제약 조건 추가

    AutoLayout이 혼동하지 않도록, 다음과 같이 stackView와 footerBar 간의 관계를 명확히 한다.

    footerBar.topAnchor.constraint(greaterThanOrEqualTo: stackView.bottomAnchor, constant: 20)
    

    이는 UIKit이 임의로 제약을 해제하지 않도록 돕는다.

    2. viewDidLayoutSubviews()에서 gradientLayer 프레임 재조정

    버튼이 오토레이아웃 기반으로 렌더링되는 경우, 초기 프레임은 .zero일 수 있다. 따라서 다음과 같이 gradient 레이어를 재조정해야 한다.

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        gradientLayer?.frame = importButton.bounds
    }
    

    3. 버튼 존재 유무 및 초기화 시점 검증

    buttonsBar.configure() 호출 직후 버튼 배열이 비어 있는 경우를 대비하여 guard let으로 예외 처리한다.


    보이지 않는 UIButton 문제를 피하는 추가 팁

    • 버튼이나 뷰의 .isHidden 속성이 예상치 않게 true로 설정되지 않았는지 확인
    • clipsToBounds = true 상태에서 gradient나 sublayer가 뷰 프레임을 벗어나지 않는지 확인
    • buttonsBar 같은 커스텀 컴포넌트의 내부 구현에서 translatesAutoresizingMaskIntoConstraints = false가 빠져 있으면 제약이 적용되지 않을 수 있음
    • Constraint 충돌 디버깅을 위해 Xcode에서 UIViewAlertForUnsatisfiableConstraints 심볼릭 브레이크포인트 설정

    마무리: UIKit 레이아웃 문제는 명확하게 제약을 정의하자

    UIKit은 강력한 레이아웃 시스템을 제공하지만, 시스템의 자동화된 판단에 맡길 경우 예기치 못한 결과가 발생할 수 있다. 특히 UIButton과 같은 핵심 인터랙션 요소가 보이지 않게 되는 문제는 단순한 화면상의 오류를 넘어 앱의 기능적 실패로 이어질 수 있다.

    레이아웃 충돌을 방지하려면 명확하고 일관된 제약 정의, 뷰 프레임의 유효 시점에서 스타일 적용, 그리고 UIView 계층과 제약 조건을 의도적으로 구성하는 습관이 필수적이다.