EEYatHo 앱 깎는 이야기

Swift ) setNeedsLayout, layoutIfNeeded - EEYatHo iOS 본문

iOS, Swift

Swift ) setNeedsLayout, layoutIfNeeded - EEYatHo iOS

EEYatHo 2021. 4. 6. 13:23
반응형

iOS에서의 View가 업데이트되는 과정

iOS에서는 앱이 구동될 때,

UIApplication의 싱글톤 인스턴스가 메인 쓰레드에서 Main Run Loop라는 이벤트 처리 루프를 실행시키고,

Main Run Loop중, Update Cycle에서 View들을 배치하고(layout), 보여주고(display) 제약합니다(constraints).

( UI관련 업데이트가 메인 쓰레드에서만 이루어 져야 하는 이유이기도 합니다. )

( layout이란, 해당 뷰의 크기와 부모뷰에 대해 어느 위치에 있는지를 뜻합니다. )

( display에는 뷰의 색, 텍스트, 이미지, Core Graphics 그리기 등이 있습니다. )

 

그런데 메모리에 존재하는 모든 View들을, 매 Update Cycle마다 체크하는 것은 당연히 낭비입니다. 

한 사이클에서 실제로 업데이트가 필요로하는 뷰는 끽해야 한두개인 경우가 많을테니까요.

 

때문에, 특정 뷰에 업데이트가 필요한 뷰라고 마킹하고,

마킹된 뷰만 Update Cycle에서 업데이트하는 절차를 기본적으로 가집니다.

 

이때, 특정 뷰가 업데이트가 필요하다고 마킹하는 함수가 setNeedsLayout입니다.

 

Update Cycle에서 마킹된 View에게 새로 업데이트 하도록 실행하는 함수는 layoutSubViews 입니다.

( layoutSubViews는 마킹된 View뿐만아니라, SubView들까지 모두 새로 업데이트하게 됩니다. )

( layoutSubViews에 의해 업데이트된 뷰를 소유한 ViewController에서는 viewDidLayoutSubviews가 호출되게 됩니다. )


시스템이 자동으로 마킹해주는 경우 ( Automatic Refresh Trigger )

하지만 개발하면서 setNeedLayout을 사용해서

"이 View는 다음 Update Cycle에 업데이트 해줘!"

라고 마킹하지 않아도, 뷰를 잘 그리는 경우가 대부분입니다.

 

왜냐하면, 아래의 5가지 경우에는 시스템이 알아서 해당 View를 마킹해주기 때문입니다.

 

1) 뷰의 크기를 조절하는 경우

2) SubView를 추가하는 경우

3) 스크롤 하는 경우

4) Orientation이 변하는 경우 ( 기기의 세로 가로 전환 )

5) 뷰의 Constraint가 변경되는 경우


Update Cycle을 기다리지 않고 즉시 업데이트해야하는 경우

setNeedLayout을 통해 비동기적으로 한번에 View를 업데이트하는 것이 아닌,

즉시 내가 설정한 Constraint대로 View를 움직여야하는 경우가 있습니다.

바로 애니메이션을 구현할 때 입니다.

 

애니메이션하려고 세팅한 도착지점이 있고, 이를 setNeedLayout으로 업데이트할 경우,

뷰가 서서히 움직이지않고, 도착지점으로 뿅!하고 가버립니다.

 

이렇게 다음 Main Run Loop 사이클까지 기다리지않고,

View의 업데이트를 바로, 동기적으로 실행할 수 있는 함수가 layoutIfNeeded입니다.

 

다음은 애니메이션에서 SnapKit을 이용해 Constraint를 변경한 뒤, layoutIfNeeded로 트리거하는 코드 입니다.

UIView.animate(withDuration: 0.5, animations: {
    // 위로 올리기
    container.snp.updateConstraints {
        $0.bottom.equalTo(window.safeAreaLayoutGuide).offset(-60)
    }
    container.superview?.layoutIfNeeded()
}, completion: nil)
Comments