출시 프로젝트를 하면서 compositional layout을 사용하며 만난 오류를 해결하며 알게 된 내용을 정리해보고자 한다!
Issue
셀에 들어갈 데이터에 맞게 동적으로 높이를 지정해야 했는데, 레이아웃 구성 시 아무리 estimated를 지정해줘도 높이가 처음부터 알맞게 들어가지 않았다.
여러 방법을 사용했지만 오른쪽 하단 날짜 레이블의 높이가 처음엔 맞지 않았고, 다른 날짜를 탭 후 다시 돌아오면 높이가 알맞게 들어오는 것을 알 수 있다.
해결!
layoutIfNeeded() 를 호출하여 문제를 해결하였다.
추정치는 말 그대로 추정하여 높이를 설정하는 것이기 때문에 처음에 정확하게 들어갈 수 없었고, 셀에 데이터가 삽입 된 이후에 레이아웃 업데이트 요청을 해야했던 것이다..
View의 Drawing Cycle에 따라 데이터 삽입 후 **layoutIfNeeded()**를 통해 즉각적 업데이트 요청을 해야했던 것!
문제 해결을 한 기념으로 View Drawing Cycle에 대해 알아보기로 했다.
💡 View Drawing Cycle
View가 로드되거나 변경이 생겼을 때 화면에 적용시켜 그리는 과정을 뜻한다.
변경이 되었다고 바로 업데이트를 수행하는 것이 아니라, Main Run Loop에 의해 이벤트를 처리할 권한을 위임받고, Drawing Cycle이 돌아오는 시점에 업데이트를 수행하게 된다.
✅ Main Run Loop와 Update Cycle
- 앱이 실행되면 UIApplication이 메인 스레드에서 Main Run Loop를 실행한다.
- main run loop는 터치 이벤트 등 여러 이벤트들을 처리한다.
- main run loop가 앱에서 발생하는 여러 이벤트를 받아, 각 이벤트에 알맞는 핸들러에게 권한을 위임한다.
- 이벤트를 모두 처리하고 권한이 다시 main run loop로 돌아오게 되는데, 이 시점을 update cycle이라고 한다.
main run loop가 받은 이벤트를 받은 즉시 실행하는 것은 아니다. 모든 핸들러가 수행을 완료하고, 다시 main run loop로 권한이 돌아오는 update cycle 시점에 변화를 적용한다.
즉 실제로 반영되기 까지 시간차가 존재한다.
💡Update Cycle을 제어하는 메서드
✅ layoutSubViews()
- view의 값을 호출한 즉시 변경시켜주는 메서드이다.
- 호출되면 해당 view의 모든 subview들의 layoutSubViews()도 호출된다.
- layoutSubViews()가 호출되면 변경사항이 없는 서브 뷰들도 다시 그리게 되기 때문에 비용이 많이 드는 메서드이다.
- 이러한 이유로 직접 호출하는 것이 지양된다‼️
- layoutSubViews()는 시스템에 의해 **적절한 시점(update cycle)**에 자동으로 호출된다.
하지만 즉시 변경된 레이아웃이 반영되어야 하는 경우 layoutSubViews()를 호출해야 하는데, 간접적으로 호출할 수 있는 메서드가 존재한다.
✅ setNeedsLayout()
- 이 메서드는 비동기로 작동하는 메서드로, 호출 시 다음 update cycle에layoutSubViews()를 호출하도록 예약하고 바로 반환된다.
- 레이아웃을 업데이트 해야한다고 알려주고 반환하는 것!
- 호출 즉시 반영되는 것이 아니라 다음 update cycle에 들어갔을 때 반영이 된다.
- layoutSubViews()를 호출하는 방법 중 가장 비용이 적게 든다.
✅ layoutIfNeeded()
- setNeedsLayout()과 비슷하게 간접적으로 layoutSubViews() 호출을 예약할 수 있는 메서드이지만, setNeedsLayout()과 다른 점은 동기적으로 작동하는 메서드라는 부분이다.
- 다음 update cycle이 올 때 까지 기다리는 것이 아니라 호출 즉시 layoutSubViews()를 실행하도록 하는 메서드이다.
- UI를 업데이트 하라는 명령을 main run loop의 가장 앞쪽에 넣어서 바로 ui가 변경되도록 한다.
🚨 주의
layoutIfNeeded()또한 결국 layoutSubViews()를 호출하는 것이기 때문에 비용이 많이 든다.
무조건적으로 쓰는 것 보다 setNeedsLayout()으로 처리되지 않을 경우에만 사용하도록 하자!
참고
https://velog.io/@mmim/iOS-View-Drawing-Cycle
https://ios-development.tistory.com/986
https://jeonyeohun.tistory.com/336
'iOS > 💻 iOS Study' 카테고리의 다른 글
RxSwift 왜 사용?? (0) | 2023.12.28 |
---|---|
[Swift] DI 의존성 주입 (1) | 2023.12.19 |
[iOS/Swift] MapKit - 위치 권한 설정을 구현해보자! (0) | 2023.10.01 |
UserDefaults와 Sandbox System (0) | 2023.08.02 |
iOS 13 이후의 앱의 라이프 사이클 & available (0) | 2023.07.30 |