[iOS] The View Drawing Cycle: 뷰 그리기 사이클
View and Window Architecture
The View Drawing Cycle
UIView 클래스는 컨텐츠를 표시하기 위해 on-demand(역주: 요구가 있을 때 언제든지) 그리기 모델을 사용합니다.
화면에 처음 뷰가 나타나면, 시스템은 뷰에게 컨텐츠를 그리라고 합니다.
시스템은 이 컨텐츠의 스냅샷을 캡처하고 해당 스냅샷을 뷰의 시각적 표현으로 사용합니다.
뷰의 내용을 변경하지 않으면, 뷰의 그리기 코드가 다시 호출되지 않을 겁니다.
스냅샷 이미지는 보기를 포함하는 대부분의 작업에 재사용됩니다.
컨텐츠를 변경하면, 뷰가 변경되었음을 시스템에 알립니다.
그런 다음 뷰는 뷰 그리기 과정을 반복하고 새로운 결과의 스냅샷을 저장합니다.
뷰의 컨텐츠가 변경될 때, 변경 내용을 직접 다시 그리지 않습니다.
대신 setNeedsDisplay() 또는 setNeedsDisplay(_:) 메서드를 사용하여 뷰를 비활성화합니다.
이 메서드는 시스템에게 뷰의 컨텐츠가 변경되었음을 알리고, 다음 기회에 다시 그려져야한다는 것을 알립니다.
시스템은 그리기 작업을 시작하기 전에 현재 실행 루프가 끝날 때까지 기다립니다.
이 지연을 통해 여러 뷰를 무효화하고, 추가, 숨기기, 리사이즈, 재배치를 한번에 할 수 있게 합니다.
이런 모든 변경 내용이 동시에 반영됩니다.
참고: 뷰의 geometry를 변경해도 시스템은 뷰의 컨텐츠를 자동으로 다시 그리지 않습니다.
뷰의 contentMod는 뷰의 geometry에 변화를 어떻게 해석할지 정합니다.
대부분의 컨텐츠 모드는 뷰 경계 내에서 기존 스냅샷을 늘리거나 재배치하며 새 스냅샷을 생성하지 않습니다.
컨텐츠 모드가 뷰의 drawing cycle에 미치는 영향에 대한 자세한 내용은 Content Modes 를 보세요.
뷰의 내용을 렌더링하는 시간이 되면 실제 그리기 프로세스는 뷰와 뷰 configuration(설정)에 따라 달라집니다.
시스템 뷰는 일반적으로 내용을 렌더링하기 위해 private 그리기 메서드를 구현합니다.
시스템 뷰는 종종 뷰의 실제 모양을 설정하는 데 사용할 수 있는 인터페이스를 표시합니다.
커스텀 UIView 서브클래스의 경우 일반적으로 뷰의 draw(_:) 메서드를 override하고, 이 메서드를 사용하여 뷰의 컨텐츠를 그립니다.
underlying 레이어의 컨텐츠를 직접 세팅하는 식의 방법도 있지만 draw(_:) 메서드가 가장 일반적인 방법입니다.
커스텀 뷰에 대한 내용을 그리는 방법에 대한 자세한 내용은 Implementing Your Drawing Code을 보세요.
iOS Drawing Concepts
The View Drawing Cycle
UIView 클래스의 서브클래스는 기본 그리기 모델에는 on-demand 컨텐츠 업데이트가 포함됩니다.
UIView 클래스는 업데이트 프로세르르 더 쉽고 효율적으로 만듭니다.
하지만 생성한 업데이트 요청들을 모으고, 적절한 시기에 그리기 코드를 전달합니다. (역주: 바로 안보낸다는 뜻)
뷰가 처음 표시되거나 뷰의 일부를 다시 그려야 할 때, iOS는 뷰의 draw(_:) 메서드를 호출하여 뷰에 콘텐츠를 그리도록 합니다.
뷰 업데이트를 유발하는 액션:
- 이동하거나 뷰를 부분적으로 가리던 다른 뷰를 제거하기
- 숨겨진 뷰를 다시 보이게 바꾸기, isHidden 을 false로 (역주: swift 기준)
- 스크린 밖으로 스크롤 했다가 다시 스크린에 보이게 하기
- 명시적으로 setNeedsDisplay() 또는 setNeedsDisplay(_:) 메서드 호출하기
*시스템 뷰는 자동으로 다시 그려집니다.
커스텀 뷰의 경우 draw(_:) 메서드를 override해야하고 모든 그리기를 이 안에 넣어야합니다.
draw(_:) 메서드에서 모양을 그리거나 문자, 이미지, 그라디엔트, 또는 다른 비주얼 컨텐츠 등 native 그리기 기술을 사용합니다.
뷰가 처음으로 보여지게 되면 iOS는 뷰의 전체 표시 영역을 포함하는 직사각형을 draw(_:) 메서드에 전달합니다.
이후의 call에서는 뷰가 실제로 다시 그려질 부분의 rect만 포함합니다.
성능을 최대화하려면 영향을 받는 컨텐츠만 다시 그려야 합니다.
draw(_:) 메서드를 호출하고 나면, 뷰는 자신을 업데이트된 것으로 표시하고 새로운 액션이 도착하여 다른 업데이트 사이클을 트리거할 때까지 기다립니다.
뷰에 정적 내용이 표시되는 경우 스크롤 이나 다른 뷰의 존재가 야기하는 뷰의 보여지는것의 변경에 응답하기만 하면 됩니다.
뷰의 컨텐츠를 바꾸길 원한다면 뷰에게 컨텐츠를 다시 그리라고 해야합니다.
setNeedsDisplay() 또는 setNeedsDisplay(_:) 메서드를 호출하여 업데이트를 트리거합니다.
예를 들어, 1초에 여러 번 콘텐츠를 업데이트하는 경우 뷰를 업데이트하는 타이머를 설정할 수 있습니다.
user interactions 또는 뷰 내부의 새로운 컨텐츠의 생산에 반응하여 뷰를 업데이트할 수도 있습니다.
중요: 뷰의 draw(_:)를 직접 호출하지 마십시오.
이 메서드는 iOS에 내장된 코드로만 호출해야 합니다.
그래픽 콘텍스트가 존재하지 않는 경우도 있기 때문에 그릴 수 없습니다.
*시스템에서 제공하는 View들은 내부 프로퍼티가 바뀌면 대부분 setNeedsDisplay를 자동으로 호출합니다.
하지만 Custom으로 만든 View들의 내부 프로퍼티가 변경되었을 때 뷰를 업데이트하고 싶다면 setNeedsDisplay를 호출해야한다는 것입니다.
또한, 이 업데이트는 다음 그리기 주기에 그려지게 됩니다.