setNeedsLayout과 setNeedsDisplay 이름은 비슷한데 어떤 차이점이 있을까?
애플공식문서를 참고하였습니다. 오역된 부분이 있을 수 있습니다. 참고해주세요😀
이 두 메소드를 비교하기 전에 main run loop부터 알아봅시다.
기기에서 앱아이콘을 터치하게 되면 @main 을 찾아 UIApplication객체와 AppDelegate객체를 생성합니다. 그리고는 이내 main run loop가 실행됩니다. main run loop는 터치 이벤트, 위치의 변화, 디바이스의 회전 등의 각종 이벤트들을 처리하게 됩니다. 이러한 처리 과정은 각 이벤트들에 알맞는 핸들러를 찾아 그들에게 권한을 처리 권한을 위임하며 진행됩니다.
발생한 이벤트들을 모두 처리하고 권한이 다시 main run loop로 돌아오는 시점을 update cycle이라고 합니다.
main run loop에서 이벤트가 처리되는 과정에서 버튼을 누르면 크기나 위치가 이동하는 애니메이션과 같이 layout이나 position 값을 바꾸는 핸들러가 실행될 때도 있습니다. 이러한 변화는 즉각적으로 반영되는 것이 아닙니다.
시스템은 이러한 layout이나 position이 변화되는 View를 체크합니다. 그리고 모든 핸들러가 종료되고 main run loop로 권한이 다시 돌아오는 시점인 update cycle에서 이런 View들의 값을 바꿔주어 position이나 layout의 변화를 적용시킵니다.
이러한 시간차가 존재하는것을 인지해야 setNeedsLayout를 쉽게 이해할 수 있습니다.
layoutSubviews는 UIView의 인스턴스 메소드입니다. 이 메소드가 호출되면 해당 view와 subView들이
모두 연달아 호출됩니다. 이는 비용이 많이 들기 때문에 직접 호출하는것은 지양해야 합니다. 이 메소드는 view의 값이 재계산되어야하는 적절한 시점에 시스템에 의해 자동으로 호출됩니다.
추가로 UIViewController내의 view가 layoutSubviews()
메소드를 호출하게 되면 값이 갱신되고 이후 UIViewController의 viewDidLayoutSubviews()
가 호출됩니다. 갱신된 view의 값에 의존하는 행위들은 이 메소드 내에 명시해줘야 합니다.
다음과 같은 상황에서는 시스템이 자동으로 size 혹은 position이 변경되야하는 view라고 체크를 하고 update cycle에서는 layoutSubviews()
가 호출되어 체크된 view들의 변경사항을 반영합니다.
위에 나열된 시점에는 자동으로 update cycle에서 layoutSubviews()
를 호출하는 행위를 예약하는 것입니다. 그렇다면 수동으로 예약하려면 어떻게 해야할까요?
이제 setNeedsLayout가 나옵니다.
Invalidates the current layout of the receiver and triggers a layout update during the next update cycle.
func setNeedsLayout()
뷰의 하위 뷰들의 레이아웃을 조정하고 싶을 때 메인스레드에서 이 메소드를 호출하세요. 이 메소드는 요청을 기록하고 즉시 반환합니다. 왜냐하면 이 메소드는 강제로 즉시 업데이트하지 않고 다음 업데이트 주기를 기다리기 때문에 여러 뷰들이 업데이트 되기 전에 여러 뷰들의 레이아웃을 무효화 시킬 수 있습니다. 이 동작을 통해 모든 레이아웃 업데이트를 하나의 업데이트 주기로 통합할 수 있으며 일반적으로는 성능이 더 좋습니다.
이 메소드를 호출한 view는 재계산이 필요한 view라고 시스템에게 알려주며 이후 update cycle에서 layoutSubviews()
가 호출됩니다.
setNeedsLayout메소드와 setNeedsDisplay메소드를 비교하였지만 이름만 비슷하지 행동은 전혀 다릅니다.
Marks the receiver’s entire bounds rectangle as needing to be redrawn.
func setNeedsDisplay()
이 메소드 혹은 setNeedsDisplay(_:)
를 사용하여 view의 컨텐츠를 다시 그려야한다고 시스템에게 알려줄 수 있습니다. 이 메소드는 요청을 기록하고 즉시 반환합니다. view는 다음 드로잉 주기가 오기 전까지는 그려지지 않습니다. 다시말해 모든 view가 업데이트 되야 다시 그려집니다.
setNeedsDisplay가 호출 된 후 다음 업데이트 주기가 되고 draw메소드가 호출 될 때 해당 뷰의 업데이트들이 한번에 이뤄집니다.
If your view is backed by a CAEAGLLayer object, this method has no effect. It is intended for use only with views that use native drawing technologies (such as UIKit and Core Graphics) to render their content.
CAEAGLLayer 객체를 사용하는 경우, 이 메소드는 효과가 없다고 합니다.
컨텐츠의 내용이나 모양이 변경될 때만 다시 그려질수있도록 이 메소드를 호출해야 합니다. 만약 view의 기하학적인 부분만 변한다면 view는 다시 그려지지 않습니다. 이 때는 메소드 호출 대신 contentMode속성을 변형하여 사용합니다.
setNeedsLayout()메소드와 setNeedsDisplay() 메소드 모두 호출 즉시 실행되지 않고 다음 update cycle에 변경사항이 적용됩니다. setNeedsLayout은 layoutSubview메소드를, setNeedsDisplay는 draw메소드를 시스템이 호출하게끔 유도한다. setNeedsLayout()메소드는 모든 핸들러가 종료되고 권한이 main run loop로 돌아오는 시점에 view의 position이나 layout에 관한 변화를 적용시키고 setNeedsDisplay()메소드는 다음 드로잉 사이클이 오면 그 때 쌓여있는 그려야할 컨텐츠들을 동시에 적용시킵니다.
출처:
https://baked-corn.tistory.com/105
https://developer.apple.com/documentation/uikit/uiview/1622601-setneedslayout/
https://developer.apple.com/documentation/uikit/uiview/1622437-setneedsdisplay/