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] 네트워크 통신으로 이미지 받아오기  (2) 2023.11.26
[iOS/Swift] MapKit Annotation displayPriority 지정하기  (1) 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
  • 인기 글

  • 최근 글

  • 태그

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

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

티스토리툴바