iOS에서 메인 쓰레드는 1초에 60번 ~ 120번(기기의 Hz마다 다르다) 화면을 다시그린다.
무조건 60번, 120번을 다시 그리는 게아니라 필요한 경우! 화면을 다시그린다.
화면을 그리는 동안엔 아래와 같은 함수 호출 싸이클이 생긴다.
updateConstraints() ➡️ layoutSubviews() ➡️ draw()
updateConstraints (오토레이아웃이 업데이트 되야 할 때에만)
- 제약: 오토레이아웃을 업데이트 한다.
- 현재 기기의 화면 크기를 기준으로 제약을 업데이트한다.
- 동적인 오토레이아웃 변경이 일어날 경우 제약조건을 변경한다.
- 명시적으로 호출할 순 없다.
- 오토레이아웃으로 인한 제약이 확정되는 시기이다.
// 테이블 뷰 셀 같은 컴포넌트 요소를 코드로 구성할 때 활용할 수 있다.
// updateConstraints에서 레이아웃 제약이 확정된다.
override func updateConstraints() {
setConstraints() // 오토레이아웃을 설정하는 함수
super.updateConstraints()
}
//반드시 super.updateConstraint()를 오토레이아웃 설정 후에 호출해야한다. 출처 - document
직접 호출이 아닌 updateConstraints를 호출할 수 있도록 예약하는 형태의 메서드가 존재한다.
setNeedsUpdateConstraints() / updateConstraintsIfNedded()
layoutSubviews()
- (하위뷰의) 레이아웃: 위치 / 크기를 재조정한다.
- frame 기준으로 알 수 있는 시점 / 하위 뷰들의 frame등 직접 설정이 가능한 시기
- 뷰 들의 레이아웃 프레임이 정해지는 시기이다.
- 호출하면 해당 View의 모든 subView들이 layoutSubviews()를 연달아 호출한다.
- 소모되는 비용이 너무 크기 때문에 직접호출은 하지않는다.❌
// 테이블 뷰 셀 같은 컴포넌트 요소를 코드로 구성할 때 활용할 수 있다.
// 오토레이아웃(제약)으로 인해 뷰들의 frame(크기)가 정해지는 시점이기 때문에 정해진 크기로 인한 작업들을 할 수 있다.
override func layoutSubviews() {
super.layoutSubviews()
self.mainImageView.clipsToBounds = true
self.mainImageView.layer.cornerRadius = self.mainImageView.frame.width / 2
}
그렇기 때문에 직접 호출이 아닌 layoutSubView를 호출할 수 있도록 예약하는 형태의 메서드가 존재한다.
setNeedsLayout() / layoutIfNedded()
draw
- 실제로 화면을 다시 그리는 단계: 실제 내부의 컨텐츠를 다시 그린다.
이 3개의 함수가 호출되는데 자동으로 호출되는데, 1초에 화면을 60번 다시그린다면 이 3개의 함수의 호출이 1초에 60번마다 일어난다는 것이다.
하지만 애플은 updateConstraints, layoutSubviews, draw는 Update Cycle에서 수행되는게 더 바람직 하므로 직접 호출하지 말라고한다.
setNeedUpdateConstraints(), setNeedsLayout(), layoutIfNeeded(), setNeedsDisplay()
그래서 존재하는 것이 setNeedUpdateConstraints(), setNeedsLayout(), layoutIfNeeded(), setNeedsDisplay() 이다.
이 메서드들은 각각 아래와 같은 업데이트를 명시적으로 예약한다.
setNeedUpdateConstraints() => 제약
setNeedsLayout(), layoutIfNeeded() => Layout
setNeedsDisplay() => Display
이들이 호출되면 시스템은 이를 체크해두고 부른 메서드에 맞게 Update Cycle에서 updateConstraints, layoutSubviews, draw를 호출하게 된다.
이를 직접 호출하지 않아도
- View의 크기 변경
- SubView 추가
- ScrollView에서 Scroll발생
- 디바이스 회전으로 인한 화면 표시 모드 변경
- View의 제약 변경
과 같은 상황에서는 자동으로 호출된다. 그래서 setNeedsLayout(), layoutIfNeeded(), setNeedsDisplay()를 직접 호출하지 않아도 UI가 업데이트된 것이다.
UpdateCycle을 기다리지 않아도 layoutIfNeeded(), setNeedsDisplay()를 호출하면 바로 View를 업데이트하게된다.
layoutIfNeeded()는 Constraints를 통해 애니메이션을 구성하고 싶을 때 유용하게 사용된다.
단순 Constarint를 변경하는 애니메이션을 만들 경우 이에대한 처리는 Update Cycle에서 처리되기 때문에 애니메이션 효과를 줄 수 없다.
하지만 Constraint 변경 후 layoutIfNeeded()메서드를 애니메이션 코드에 추가하면 layoutIfNeeded() 가 순차적으로 처리되며 애니메이션을 확인할 수 있게된다.