Featured image of post Auto Layout(4) - Debugging Auto Layout

Auto Layout(4) - Debugging Auto Layout

Type of Errors

  1. 충족되지 않은 레이아웃 - constrain만으로 충분하지 않은 경우
  2. 애매한 레이아웃 - 제약이 많아서(중복된 제약이 있어서) 어떤 것을 선택해야 할 지 모르는 경우
  3. 논리적 오류 - (사람의) 논리적 오류

Unsatisfiable Layouts 충족되지 않은 레이아웃

img

붉은색 화살표를 따라가면 어떤 제약이 충족되지 않는지 알 수 있다.

  • 시스템이 런타임중에 충족되지 않은 레이아웃이 감지하면 아래 세가지를 진행한다.

    1. 충돌이 일어난 제약을 알아내고
    2. 유효한 레이아웃을 찾을 때까지, 충돌이 일어난 제약을 하나씩 파괴해 보고
    3. 콘솔창에 충돌 및 깨진 제약에 대한 로그를 남긴다
  • 충족되지 않은 제약조건을 예방하는 방법은 다음과 같다.

    • 뷰 계층 구조에 프로그래밍 방식으로 뷰를 추가할 때 만족할 수 없는 제약 조건이 자주 발생한다.
      • 코드로 뷰를 그릴 때에 translatesAutoresizingMaskIntoConstraints 메서드를 false로 설정해야 하는데, 이를 놓치는 경우가 많다.
      • 보여주고 싶은 뷰가 너무 작은 공간에 표시될 때, 자주 발생할 수 있다.
        ➡️ 최소 공간을 예측해서 만들거나, 그렇게 할 수 없는 경우에는 필수 제약 조건을 높은 proirity로 설정해서 방지할 수 있다.

Ambiguous Layouts 애매한 레이아웃

두 개 이상의 가능성을 가지고 있을 때 애매한 레이아웃이라고 한다.

  • 애매한 레이아웃을 발견할 수 있는 방법

    breakpoint를 걸고 lldb 디버깅 메서드를 이용해서 확인할 수 있다.

    hasAmbiguousLayout - 애매한 레이아웃을 가지고 있는지 확인하고 true/false를 반환한다.
    exerciseAmbiguityInLayout - 애매한 레이아웃이 해결된 화면으로 바꾼다. constraintsAffectingLayoutForAxis - 지정된 축을 따라 레이아웃에 영향을 주는 제약의 배열을 반환한다. _autolayoutTrace - 해당 보기를 포함하는 전체 보기 계층 구조에 대한 진단 정보가 포함된 문자열을 반환한다.

Logical Errors 논리적 오류

사람의 실수로 인해 발생하는 오류이다.

  • 기존에 걸려있는 제약을 검토하여 빠지거나 중복되는 제약이 있는지 확인
  • 컨텐츠 크기가 중요한 경우 CH, CR 우선순위를 높게 설정
  • 충돌이 날 때까지 명시젝 제약 조건을 추가하여 명확하게 만든다
  • 문제 발생 시 다른 대체 제약 조건을 추가하여 해결

Debugging Tricks and Tips

Log 이해

로그를 이해하면 디버깅을 더 쉽게 할 수 있다. 로그 해석이 어려운 경우 로그를 복사하여 Why The Failure, Auto Layout에 븉여 넣어보자

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
2015-08-26 14:27:54.790 Auto Layout Cookbook[10040:1906606] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
    "<NSLayoutConstraint:0x7a87b000 H:[UILabel:0x7a8724b0'Name'(>=400)]>",
    "<NSLayoutConstraint:0x7a895e30 UILabel:0x7a8724b0'Name'.leading == UIView:0x7a887ee0.leadingMargin>",
    "<NSLayoutConstraint:0x7a886d20 H:[UILabel:0x7a8724b0'Name']-(NSSpace(8))-[UITextField:0x7a88cff0]>",
    "<NSLayoutConstraint:0x7a87b2e0 UITextField:0x7a88cff0.trailing == UIView:0x7a887ee0.trailingMargin>",
    "<NSLayoutConstraint:0x7ac7c430 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7a887ee0(320)]>"
)

Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7a87b000 H:[UILabel:0x7a8724b0'Name'(>=400)]>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

img ( )에 있는 메세지를 복사해서 wtf 사이트에 붙여넣기 하고 Go 버튼을 누르면 로그를 해석해준다.

img 어떤 제약조건이 있는지 도식화해서 보여주기 때문에 디버깅을 수월하게 할 수 있다.

Log에 식별자 추가

UILabel:0x7b58b040'Name'.leading과 같이 identifier(Name)를 추가하여 로그를 보기 쉽게 만들 수 있다.

img
UIView 요소에 identifier를 추가하려면 identity inspector > Accessibility > identifier에 이름을 넣어주면 된다.

img
제약에 identifier를 추가하려면 스토리보드에서 제약을 클릭하고 attributes inspector > identifier에 이름을 넣어주면 된다.

시뮬레이터에서 뷰와 제약 시각화하기

XCode메뉴 > Debug > View Debugging > show Alignment Rectangles 체크하면 시뮬레이터 상에서 뷰 가장자리와 제약을 시각화 할 수 있다.

img

Xcode Debug bar에서 Debug View Hierarchy button을 클릭하면 뷰 계층을 볼 수 있다. img

Reference

Auto Layout Guide
야곰닷넷 - 오토레이아웃 정복하기