본문 바로가기
공부/Apple

[Swift] Update Cycle

by 초코팅촉 2024. 9. 22.
728x90

이번에는 생명주기와는 또 다른 Update Cycle에 대해 알아보고자 합니다.(굳이 번역하면 갱신주기정도로 말할 수 있겠네요.)

 

제가 이걸 알고 찾아보게 된 게 커스텀 세그먼트를 만들고 다크모드에 대응하면서부터였는데요,

커스텀 세그먼트를 만들 때 그냥 만들었는데 다크모드를 갔다 오니까 커스텀 세그먼트에 버그가 생기더라구요,

암튼 이 얘기는 나중에 더 쓰도록 하구요,

결과부터 얘기하면 gpt에서는 `viewDidLayoutSubviews()`를 쓰라고 하더라고요.

저 메소드에 대해 찾아보면서 그와 유사하지만 별개로 새로 알게 된 내용들을 정리해봤습니다.

 

Main Run Loop

viewDidLayoutSubviews 메서드는 layoutSubviews가 끝난뒤에 실행된다고 하더라구요,

여기서 layoutSubviews는 Update Cycle에 속해있는데요, 이 친구는 Main Run Loop가 끝난 다음에 실행됩니다.

그렇다면 일단 Main Run Loop가 뭔지 확인해 봐야겠죠?

 

우선 Main Run Loop는 다음과 같은 일을 합니다.

- 이벤트 관찰 및 이벤트 처리

- 처리한 이벤트들을 각 핸들러에 맞춰 위임

각 앱이 실행될 때 메인 스레드가 하나씩 생성되고 이때 각종 이벤트의 발생에 대응하기 위해 Main Run Loop가 하나씩 생성됩니다.

1. Main Run Loop에서는 이벤트를 관찰하고 이를 애플리케이션 객체에 넘기고,

2. 어플리케이션 객체에서는 하나씩 가져온 이벤트를 담당해 처리할 수 있는 handler를 보유한 Core Obejct에게 넘깁니다.

3. Core Object의 handler는 개발자의 코드를 호출합니다.

 

이 일련의 과정들이 끝난 뒤에 Update Cycle이 시작됩니다.

 

Update Cycle

Update Cycle에선 앞에서 계산된 값에 맞춰 UI들을 그려주게 됩니다.

layout, display, constraints 세가지를 하게됩니다. 아래는 저 세가지를 할때의 UIView 메서드 정리표입니다.

메서드 용도 Layout Display Constraints
Update(직접호출 금지) layoutSubviews draw updateConstraints
다음 Update Cycle에서
업데이트 요청
setNeedsLayout setNeedsDisplay setNeedsUpdateConstraints
invalidateIntrinsicContentSize
바로 업데이트 요청 layoutIfNeeded   updateConstraintsIfNeeded
자동 업데이트 flag 만들기 기기회전
서브뷰 추가
뷰 크기변경
스크롤뷰 스크롤
뷰의 constraint 변경
뷰의 bound 변경 뷰 계층에서 뷰 삭제
constraints 상수 / 우선순위 / 활성여부  변경

이 셋의 역할은 다음과 같이 나눠집니다.

Layout : 뷰의 크기, 위치를 설정

Display : 색, 텍스트, 이미지처럼 크기나 위치와 관련없는 속성들을 설정

Constraints : 뷰 간의 제약조건에 대해 계산하고 설정

 

Layout

layoutSubviews()

- 뷰와 자식뷰들의 위치, 크기를 재조정하는 메서드

- 재귀적으로 모든 자식뷰에 존재하는 layoutSubviews()를 호출하기에 매우 비용이 큰 메서드라서 직접호출은 금지.

- 시스템이 뷰의 크기나 위치를 조정할때 자동으로 호출되므로 오버라이딩해서 위치나 크기를 조절할때 쓸 수 있다.

 

⚠️ 뷰의 크기나 위치를 조정하는 로직을 실행하는 것은 UIView를 상속받은 클래스내부에선 layoutSubviews, UIViewController를 상속받은 클래스 내부에선 viewDidLayoutSubviews(UIViewController 메서드)의 내부에서 각각 실행해주는 것이 맞다.

 

setNeedsLayout()

- layoutSubviews를 수동으로 호출하는 메서드.

- 정확히는 다음에 돌아오는 Update Cycle의 layoutSubviews가 호출될 때 수정된 내용을 적용해달라는 flag를 꽂는 것이다.

- 다음번에 돌아올 때 적용되니까 layoutSubviews를 수동으로 호출하는 비용은 매우 적다고 합니다.

 

layoutIfNeeded()

- layoutSubviews를 수동으로 호출하는 메서드.

- 바로 layoutSubviews를 호출하는 메서드. 따라서 비용이 매우 많이 들어간다고 합니다.

- 당연하게도 변동사항이 없다면 layoutSubviews를 호출하지 않는다고 합니다.

 

Display

draw()

- layoutSubviews와는 다르게 재귀적으로 작동하지 않습니다. -> 하위뷰에는 적용되지 않음

- 마찬가지로 직접 호출은 안된다고 합니다.

 

setNeedsDisplay()

- setNeedsLayout처럼 다음번 Update Cycle이 돌아올 때 적용시켜달라고 flag를 꽂아 놓는 메서드

- 만약 UI Components에 직접적으로 연관된게 없지만 뷰를 다시 그려줘야 할 필요가 있는 경우엔 didSet에 setNeedsDisplay를 명시적으로 호출해주면 된다고 합니다.

 

Constraints

updateConstraints()

- 이 역시도 직접 호출 안됨.

- 동적으로 constraints가 변동될 필요가 있는 경우에 updateConstraints에 구현.

- 정적인 constraints는 InterfaceBuilder, View 생성자, viewDidLoad에 정의.

 

setNeedsUpdateConstraints()

- 이전의 setNeeds시리즈와는 유사하나 다음 Update Cycle에서 updateConstraints의 호출을 보장함.

 

updateConstraintsIfNeeded()

- layoutIfNeeded처럼 필요하다면(수정되어 변경이 필요하다면 -> flag가 있다면) updateConstraints를 호출하는 메서드입니다.

 

invalidateIntrinsicContentSize()

- intrinsic content size : View 내부에서 담고있는 content를 나타내기 위해 이상적으로 필요한 공간의 크기.

- 위 메서드가 호출되면 intrinsic content size가 다음 Update Cycle때 갱신되어야함을 알림-> flag를 꽂는다.

- 커스텀뷰를 만들게 되면 위 메서드를 통해 직접 관리해줘야 한다.

 

 

 

 

 

아래의 글을 참고하여 작성하였습니다.

https://ios-development.tistory.com/170

 

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

1. Main Run Loop과 Update Cycle 앱 실행시, iOS의 UIApplication이 메인 스레드에서 main run loop를 실행 - main run loop: 각종 이벤트들을 관찰하며, 그 이벤트들을 처리, 각 이벤트들에 맞는 핸들러를 찾아서 그

ios-development.tistory.com

https://skytitan.tistory.com/514

 

[iOS] 레이아웃 update cycle

[iOS] Update Cycle: 뷰 업데이트 메소드 iOS 개발을 하면서 매일 뷰와 사용자와 interaction이 가능한 다양한 UI Components를 만들지만 "View Rendnering" 에 대한 이해가 부족함을 느꼈습니다. View에 대한 이해가

skytitan.tistory.com

https://sueaty.tistory.com/162

 

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

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

sueaty.tistory.com

 

728x90