View의 Drawing Cycle

2023. 11. 11. 16:19·iOS/UIKit&SwiftUI

 

출시 프로젝트를 하면서 compositional layout을 사용하며 만난 오류를 해결하며 알게 된 내용을 정리해보고자 한다!

Issue

셀에 들어갈 데이터에 맞게 동적으로 높이를 지정해야 했는데, 레이아웃 구성 시 아무리 estimated를 지정해줘도 높이가 처음부터 알맞게 들어가지 않았다.

Untitled.pnglayout.gif

여러 방법을 사용했지만 오른쪽 하단 날짜 레이블의 높이가 처음엔 맞지 않았고, 다른 날짜를 탭 후 다시 돌아오면 높이가 알맞게 들어오는 것을 알 수 있다.

해결!

Untitled.png

layoutIfNeeded() 를 호출하여 문제를 해결하였다.

추정치는 말 그대로 추정하여 높이를 설정하는 것이기 때문에 처음에 정확하게 들어갈 수 없었고, 셀에 데이터가 삽입 된 이후에 레이아웃 업데이트 요청을 해야했던 것이다..

View의 Drawing Cycle에 따라 데이터 삽입 후 **layoutIfNeeded()**를 통해 즉각적 업데이트 요청을 해야했던 것!

문제 해결을 한 기념으로 View Drawing Cycle에 대해 알아보기로 했다.

 

 

💡 View Drawing Cycle

View가 로드되거나 변경이 생겼을 때 화면에 적용시켜 그리는 과정을 뜻한다.

변경이 되었다고 바로 업데이트를 수행하는 것이 아니라, Main Run Loop에 의해 이벤트를 처리할 권한을 위임받고, Drawing Cycle이 돌아오는 시점에 업데이트를 수행하게 된다.

✅ Main Run Loop와 Update Cycle

Untitled.png

  • 앱이 실행되면 UIApplication이 메인 스레드에서 Main Run Loop를 실행한다.
  • main run loop는 터치 이벤트 등 여러 이벤트들을 처리한다.
  • main run loop가 앱에서 발생하는 여러 이벤트를 받아, 각 이벤트에 알맞는 핸들러에게 권한을 위임한다.
  • 이벤트를 모두 처리하고 권한이 다시 main run loop로 돌아오게 되는데, 이 시점을 update cycle이라고 한다.

Untitled.png

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()

Untitled.png

  • 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 > UIKit&SwiftUI' 카테고리의 다른 글

[iOS/UIKit] 토글되는 컬렉션뷰 만들기 - NSDiffableDataSourceSectionSnapshot  (0) 2024.02.22
[iOS/Kingfisher] 네트워크 통신으로 이미지 받아오기  (1) 2023.11.26
[iOS/Swift] MapKit Annotation displayPriority 지정하기  (0) 2023.10.20
MapKit CustomAnnotation  (2) 2023.10.10
[iOS/Swift] search bar 에 테두리와 그림자 동시 적용하기 - clipsToBounds  (0) 2023.10.01
'iOS/UIKit&SwiftUI' 카테고리의 다른 글
  • [iOS/UIKit] 토글되는 컬렉션뷰 만들기 - NSDiffableDataSourceSectionSnapshot
  • [iOS/Kingfisher] 네트워크 통신으로 이미지 받아오기
  • [iOS/Swift] MapKit Annotation displayPriority 지정하기
  • MapKit CustomAnnotation
김졀니
김졀니
🍎 iOS 개발
  • 김졀니
    졀니의 개발 공부✨
    김졀니
  • 전체
    오늘
    어제
    • 분류 전체보기
      • iOS
        • Swift
        • UIKit&SwiftUI
        • RxSwift&Combine
        • WWDC
      • Study
        • 🚨 TroubleShooting
        • 🌱 SeSAC
  • 블로그 메뉴

    • 홈
    • Github
  • 인기 글

  • 최근 글

  • 태그

    FileManager
    layoutIfNeeded
    mapkit
    displayPriority
    CLLocation
    actor
    RxSwift
    traits
    pointfree
    swift concurrency
    kingfisher header
    Drawing Cycle
    OperationQueue
    observable
    Realm
    @PropertyWrapper
    동시성프로그래밍
    이미지 캐싱
    wwdc23
    위치 권한
    의존성 주입
    Swift
    concurrency
    ReactorKit
    Sendable
    ios
    clipstobounds
    인앱리뷰
    mainactor
    swiftdata
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
김졀니
View의 Drawing Cycle
상단으로

티스토리툴바