본문 바로가기
iOS/설명

[iOS] 레이아웃 update cycle

by Sky Titan 2022. 4. 18.
728x90
 

[iOS] Update Cycle: 뷰 업데이트 메소드

iOS 개발을 하면서 매일 뷰와 사용자와 interaction이 가능한 다양한 UI Components를 만들지만 "View Rendnering" 에 대한 이해가 부족함을 느꼈습니다. View에 대한 이해가 부족하니 문제 해결도 잘 안됐던

sueaty.tistory.com

 

[번역] iOS 레이아웃의 미스터리를 파헤치다

iOS의 UIView가 그려지는 과정과 메소드들을 살펴봅니다.

medium.com

Main Run Loop

  • main run loop는 유저로부터 모든 input 이벤트를 받고 적절한 응답을 해준다.
  • 때문에 유저가 발생시킨 모든 상호작용은 event queue에 추가되고 Application object는 event queue로부터 이벤트를 하나씩 꺼내어 애플리케이션의 다른 객체들에게 전달한다.
    • 즉, 애플리케이션 객체 (Application Object)는 유저로부터의 input 이벤트를 해석하고, 그에 상응하는 application 의 Core object들 안에 있는 handler를 호출한다.
    • handler들은 개발자가 쓴 코드들을 호출한다.
  • 위의 메서드들이 반환되면 Update Cycle이 다시 시작된다. 
    • Update Cycle은 View들을 배치하고 다시 그리는 역할을 한다.
순서
user의 input event 발생
Event queue에 추가
main run loop에서 event queue에 있는 event들을 꺼내어 Application object에게 넘김 (control을 넘김)
Application object들에서 event를 적절한 core object들로 넘기고 handler 실행
handler가 리턴되면 다시 control이 main run loop로 돌아오고 update cycle 실행

Update Cycle

  • Update Cycle은 application이 유저로부터의 모든 이벤트 핸들링 코드를 수행하고 다시 Main Run Loop로 컨트롤을 반환하는 지점이다.
    • 이 지점에서 시스템이 View들을 배치(layout)하고, 그리고 (display), 제약(constraint)을 건다.
    • 만약 이벤트 핸들러가 처리되는 과정에 특정 UIView에 변화가 생기면 해당 UIView는 redraw되어야 하고, 다음 Update Cycle에서 시스템이 해당 변화를 처리한다.
  • iOS앱은 초당 60프레임을 보여주기 때문에 한 번의 Update Cycle은 1/60초 정도다.
    • 굉장히 빠른 속도이기에 User는 UI와 상호작용 사이의 차이를 인지하지 못한다.
    • 하지만 이벤트가 처리되는 시점과 실제로 View가 다시 그려지는 시점엔 차이가 있기 때문에, 만약 우리가 View의 마지막 layout content에 대해 계산을 해야한다면, 예전 정보를 가지고 조작할 수 있는 가능성이 생긴다.

 

Layout


  • UIView의 크기, 위치를 의미한다.

 

layoutSubviews()

  • View와 자식뷰들의 위치, 크기를 재조정하는 메서드이다.
    • 재귀적으로 모든 자식 뷰의 layoutSubviews까지 호출하기 때문에 부하가 큰 메서드이다.
    • 그렇기에 직접 호출은 금지되어있다.
  • 시스템은 View의 frame을 다시 계산해야할 때 layoutSubview를 호출하기 때문에 layoutSubviews를 오버라이딩해서 frame이나 특정 위치, 크기를 조절할 수 있다.
  • ViewController에서는 layoutSubviews가 완료되면 viewDidLayoutSubviews가 호출된다.
  • 레이아웃의 크기, 위치와 관련된 로직을 View에선 layoutSubviews, ViewController에서는 viewDidLayoutSubviews에서 호출하는 것이 오래된 레이아웃, 위치 변수를 계산에 이용하는 실수를 막는 방법이다.

 

자동으로 layoutSubviews()가 호출되는 경우

  1. View를 Resizing
  2. SubView 추가
  3. UIScrollView를 스크롤할 때, UIScrollView와 부모뷰가 layoutSubviews호출
  4. Device 회전
  5. View의 constraint 변경

 

수동으로 layotuSubviews()를 호출하는 방법

setNeedsLayout()

  • layoutSubviews를 가장 적은 부하로 호출할 수 있는 메서드
  • 시스템에게 해당 View의 layout이 다시 계산되어야함을 알려준다.
  • setNeedsLayout은 호출 즉시 반환되고, 직접 레이아웃을 업데이트 하진 않는다.
    • 다음 Update Cycle에서 View와 자식 뷰들의 layoutSubviews가 호출되게 한다.

 

layoutIfNeeded()

  • 만약 View가 layout이 재조정되어야 한다면, 즉시 layoutSubviews를 호출한다.
  • 만약 setNeedsLayout을 호출한 직후, 혹은 자동으로 layoutSubviews를 호출해주는 방법을 쓴 이후에 layoutIfNeeded를 호출한다면 즉시 layoutSubviews가 호출된다.
    • 반대로 재조정될 이유가 없다면 호출되지 않는다.
  • setNeedsLayout과 다르게 layout 및 자식 뷰들을 즉시 다시 그리는 작업을 메서드가 반환되기 전에 실행한다.
  • Costraint를 이용한 애니메이션을 쓰는 상황에서 유용하다.
    • 애니메이션 시작전에 layoutIfNeeded를 호출해서 미리 레이아웃을 업데이트 하고 Animation 클로저 안에서 다시 layoutIfNeeded를 호출해서 애니메이션을 실행할 수 있다.

 

Display


  • View의 속성들 중 크기, 위치, 자식 뷰들에 대한 정보를 갖지 않는 속성들을 포함한다.
    • 색, 텍스트, 이미지, Core Graphic 그리기
  • Layout과정과 마찬가지로 시스템이 자동으로 업데이트하게 하는 방식, 수동으로 업데이트 하는 방식이 존재한다.

 

draw()

  • Layout업데이트 과정의 layoutSubviews와 동일한 역할
    • 차이점은 자식뷰들의 draw를 호출하지는 않는다.
  • 직접 호출은 금지

 

setNeedsDisplay

  • setNeedsLayout과 유사하다.
  • 내부 dirty플래그를 활성화하고, 다음 Update Cycle에서 해당 플래그가 활성화된 View들의 draw를 호출해서 다시 그리게 한다.
    • 일부분만 다시 그려지길 원한다면 파라미터로 rect를 전달할 수 있다. 
  • 대부분의 경우, 우리가 명시적으로 이 메서드를 호출하지 않아도 Update Cycle에 다시 그려진다.
    • 하지만 만약 UI컴포넌트에 직접적으로 연관되어 있지 않지만 매 Update Cycle마다 다시 뷰를 그리게 해야하는 속성이 있다면, didSet안에서 setNeedsDisplay를 명시적으로 호출해줄 수 있다.

 

Constraints


  • Auto Layout에서는 Layout하고 Draw하는 것에 대해 3단계의 과정이 필요하다.
    1. Constraint업데이트: 시스템이 View에 필요한 Constraints를 계산하고 설정한다.
    2. Layout단계: 레이아웃 엔진이 View들의 frame, 자식 뷰들의 frame을 계산하고 배치
    3. Display단계: View들의 컨텐츠를 다시 그린다.

 

updateConstraints

  • layoutSubviews, draw와 같이 오직 오버라이딩 되어야 하며 명시적으로 호출되면 안된다.
  • 보통 동적으로 변해야 하는 Constraint들을 구현할 때 updateConstraints안에 구현한다.
  • 정적인 Constraints는 InterfaceBuilder, View의 생성자, viewDidLoad에서 정의한다.

 

자동으로 다음 UpdateCycle에서 updateConstraints 호출하게 하는 경우

  1. Constraints를 활성화 / 비활성화하는 경우
  2. Constrinats의 priority, constant를 변경한 경우
  3. View 계층에서 View를 삭제한 경우

 

수동으로 (명시적으로) updateConstraints를 호출하게 하는 경우

setNeedsUpdateConstraints

  • setNeedsLayout, setNeedsDisplay와 유사한 역할
  • 다음 Update Cycle에서 updateConstraints호출 보장

 

updateConstraintsIfNeeded

  • layoutIfNeeded와 유사
    • 하지만 auto layout을 사용하는 뷰에만 유효
  • Constraint Update 플래그를 검사해서 업데이트 되어야 한다면 updateConstraints를 즉시 호출한다.
    • 해당 플래그는 자동 설정, setNeedsUpdateConstraints, invalidateIntrinsicContentSize를 통해 설정 가능하다.

 

invalidateIntrinsicContentSize

  • auto layout을 사용하는 일부 View들은 intrinsicContentSize속성을 가지고 있고 이것은 View가 가지고 있는 Content의 크기이다.
  • invalidateIntrinsicContentSize를 호출하면 View의 intrinsicContentSize가 다음 Update Cycle에서 재계산되어야함을 알리는 플래그를 활성화한다.

 

 

Layout, Display, Constraints의 메서드들

 

Update Cycle에서 메서드들이 호출되는 모습

 

728x90

'iOS > 설명' 카테고리의 다른 글

[iOS] Bundle  (0) 2022.04.22
[iOS] 앱 terminate되게 하는 법  (0) 2022.04.22
[iOS] autoresizingMask  (0) 2022.04.16
[iOS] KVO (Key-Value Observing)  (0) 2022.04.16
[iOS] APNs 이용해서 Push 보내기  (0) 2022.04.09

댓글