UIView가 생성되면 아래 3단계를 거치는데, 이 3단계는 단방향으로만 일어나는 것이 아니라 특정 단계가 이전 단계나 전체 단계를 다시 트리거링 할 수 있다. 한 사이클이 1/60초에 실행된다. 각 단계의 메소드들은 main run loop의 마지막 부분인 update cycle에서 호출되므로 직접 호출해서는 안된다.
Update step - updateConstraints()
하는 일: 시스템이 view에 필요한 constraint들을 계산하고 설정
호출시점
시스템이 자동으로 호출하는 경우:view hierarchy에서 bottom-up 순으로 호출
constraint 활성화/비활성화
constraint 값, 우선순위 변경
view를 view hierarchy에서 삭제
명시적으로 호출을 요청하는 방법
setNeedsUpdateConstraints(): 다음 update cycle에 호출하도록 트리거링
updateConstraintsIfNeeded(): constraint update flag가 설정(아래 방법으로 가능)되어 있다면 즉시 호출하도록 트리거링. auto layout 사용 시에만 유효.
자동으로 설정
setNeedsUpdateConstraints() 호출
invalidateIntrinsicContentSize() 호출(intrinsicContentSize가 다음 update cycle에 다시 계산되도록 함)
오버라이드
언제하는가?
최적화된 동적 constraint를 구현하고 싶을 때(정적인 constraint는 InterfaceBuilder나 view 생성자, viewDidLoad() 에서 구현)
주의할 점
super.updateConstraints() 호출할 것
Layout Step - layoutSubviews()
하는 일: 레이아웃 엔진이 view의 frame과 자식 view들의 frame을 계산하고 배치(모든 자식 view의 layoutSubviews()를 재귀호출하므로 부하가 크다)
호출 시점
시스템이 자동으로 호출하는 경우: view hierarchy에서 top-down 순으로 호출
view resizing
subView 추가
UIScrollView 스크롤될 때 scrollview와 그 부모 view에 호출
디바이스 회전
constraint 변경
명시적으로호출을 요청하는 방법
setNeedsLayout(): 다음 update cycle에 호출하도록 트리거링
layoutIfNeeded(): 즉시 호출하도록 트리거링
오버라이드
언제하는가?
constraint로는 충분하지 않을 때
frame을 직접 계산할 때
주의할 점
super.layoutSubviews() 호출할 것
setNeedsLayout()이나 setNeedsUpdateConstraints()를 호출하지 말 것(무한루프에 빠짐)
현재 view hierarchay 외부의 constraint를 수정하지 말 것
현재 view hierarchay 내부의 constraint를 수정하는 것도 Update Step과 Layout Step을 트리거링하기 때문에 무한루프에 빠지지 않도록 주의할 것
Render Step - draw(_:)
하는 일: view의 속성 중 크기나 위치를 제외한 색, 텍스트, 이미지, CoreGraphics 등을 그림(자식 view들의 draw(_:)를 호출하지 않음). auto layout 사용 여부와 관계 없음.
호출 시점
시스템이 자동으로 호출하는 경우: view hierarchy에서 top-down 순으로 호출
bounds 변경
명시적으로호출을 요청하는 방법
setNeedsDisplay(): 다음 update cycle에 호출하도록 트리거링
displayIfNeeded()는 UIView에 존재하지 않으며, CALayer, NSView, NSWindow에만 존재(다음 update cycle까지 기다리는 것만으로 충분하다고 하는데 모바일의 특성상 성능 이슈 때문이 아닐까?)