[iOS - swift] 18. setNeedsLayout, layoutIfNeeded (run loop, update cycle개념)

1. Main Run Loop과 Update Cycle
앱 실행시, iOS의 UIApplication이 메인 스레드에서 main run loop를 실행
- main run loop: 각종 이벤트들을 관찰하며, 그 이벤트들을 처리, 각 이벤트들에 맞는 핸들러를 찾아서 그들에게 권한을 위임 (버튼 클릭, 가로 모드전환, 위치 변화)
- update cycle: 이벤트 핸들러들이 처리하여 계산한 값을 토대로 UI가 실제적으로 반영되는 시점
2. setNeedsLayout과 layoutIfNeeded
- 둘 다 UIView 의 메소드
- 둘 다 최종적으로 layoutSubViews()메소드를 호출하는 예약 메소드
1) layoutSubViews()
- View의 레아아웃을 호출한 즉시 변경해주는 메소드 (단, view의 하위 뷰들도 모두 layoutSubViews()를 호출)
- update cycle에서 호출되는 메소드
- 직접 호출 하기에는 비용이 비싸므로, 직접호출은 지양
2) setNeedsLayout
- 비동기적
- 호출한 뷰와 하위 뷰들의 레이아웃을 업데이트하고 UI에 반여하고 싶을 때, 예약어 (스케줄링에 반영)
@IBOutlet var constraintButtonBottom: NSLayoutConstraint!
@IBAction func updateButtonHeight(_ sender: UIButton) {
view.layoutIfNeeded()
if self.viewHeight.constant == 3 {
self.viewHeight.constant = 5
} else {
self.viewHeight.constant = 3
}
UIView.animate(withDuration: 2.0, animations: {
self.view.setNeedsLayout() // 비동기
})
}
* 위에서 에니메이션이 안보임: setNeedsLayout은 비동기이므로 updateButtonHeight(sende_:)함수가 종료되고 실행되므로
* view.layuoutIfNeeded()를 사용하는 이유: 기존에 기다리고 있던 뷰 업데이트들을 반영시키기 위함
3) layoutIfNeeded
- 동기적
- UI를 즉시 반영하고자 할 경우 사용 (위 코드에서 setNeedsLayout()을 layoutIfNeeded()로 할 경우, updateButtonHeight가 먼저 종료되지 않음)