Rect를 그리거나 그렇지 않으면 Rect를 그리거나 하지 않습니다(drawRect/Core Graphics 대 subview/images 중 언제 사용해야 하며 그 이유는 무엇입니까?)
이 질문의 목적을 명확히 하기 위해:하위 뷰와 drawRect를 모두 사용하여 복잡한 뷰를 만드는 방법을 알고 있습니다.저는 언제 그리고 왜 하나를 다른 하나보다 더 사용해야 하는지 완전히 이해하려고 노력하고 있습니다.
또한 프로파일링을 수행하기 전에 미리 최적화하고 더 어려운 방법으로 작업하는 것은 말이 되지 않는다는 것을 이해합니다.제가 두 가지 방법에 모두 익숙하다고 생각하고, 이제 정말로 더 깊은 이해를 원합니다.
테이블 보기 스크롤 성능을 정말 부드럽고 빠르게 만드는 방법을 배우면서 많은 혼란이 생깁니다.물론 이 방법의 원래 출처는 iPhone용 트위터(이전의 트윗) 뒤에 있는 저자의 것입니다.기본적으로 테이블 스크롤을 부드럽게 하려면 하위 뷰를 사용하지 않고 모든 도면을 하나의 사용자 정의 뷰로 수행하는 것이 비결이라고 합니다.기본적으로 하위 보기를 많이 사용하면 오버헤드가 많고 상위 보기에 대해 지속적으로 재구성되므로 렌더링 속도가 느려지는 것으로 보입니다.
공정하게 말하자면, 이것은 3GS가 새 제품으로 꽤 유명했을 때 쓰여졌고, 그 이후로 iDevices는 훨씬 빨라졌습니다.여전히 이 방법은 고성능 표를 위해 웹과 다른 곳에서 정기적으로 제안됩니다.사실 이것은 Apple의 Table Sample Code에서 제안된 방법이며, 여러 WWDC 비디오(iOS 개발자를 위한 Practical Drawing for iOS)와 많은 iOS 프로그래밍 책에서 제안되었습니다.
그래픽을 설계하고 코어 그래픽 코드를 생성하는 멋진 도구도 있습니다.
그래서 처음에 저는 "코어 그래픽스가 존재하는 이유가 있습니다.빠릅니다!"
하지만 "가능하면 코어 그래픽을 선호한다"는 아이디어를 얻자마자 drawRect가 종종 앱의 응답성 저하의 원인이 되고 메모리 측면에서 매우 비용이 많이 들고 CPU에 부담이 된다는 것을 알게 되었습니다.기본적으로, 내가 "우선적으로 그리는 것을 피해야 한다" (WWDC 2012 iOS 앱 성능: 그래픽 및 애니메이션)
그래서 제 생각에는, 모든 것과 마찬가지로, 그것은 복잡합니다.저와 다른 사람들이 draw를 사용하는 시기와 이유를 이해하는 데 도움이 될 수도 있습니다. 그렇죠?
Core Graphics를 사용해야 하는 몇 가지 분명한 상황이는 다음과 같습니다.
- 동적 데이터가 있습니다(Apple의 주식 차트 예제).
- 크기 조정이 가능한 간단한 이미지로는 실행할 수 없는 유연한 UI 요소가 있습니다.
- 렌더링된 후 여러 위치에서 사용되는 동적 그래픽을 작성하는 중입니다.
Core Graphics를 피할 수 있는 상황이 보입니다.
- 보기 속성을 별도로 애니메이션화해야 합니다.
- 보기 계층이 상대적으로 작기 때문에 CG를 사용하여 인식되는 추가 노력은 얻을 가치가 없습니다.
- 전체를 다시 그리지 않고 보기 조각을 업데이트하려는 경우
- 상위 뷰 크기가 변경될 때 하위 뷰의 레이아웃을 업데이트해야 합니다.
그러니 당신의 지식을 주세요.어떤 상황에서 올바른/코어 그래픽을 그릴 수 있습니까(서브뷰를 통해서도 가능)?어떤 요인이 당신을 그 결정으로 이끌었습니까?원활한 테이블 셀 스크롤을 위해 하나의 맞춤형 뷰에 그리기를 권장하는 방법/이유는 무엇입니까? 그러나 Apple은 일반적인 성능상의 이유로 Rect를 그리기를 권장합니다.간단한 배경 이미지(크기 조정 가능한 png 이미지를 사용하는 경우와 비교하여 CG로 생성하는 경우)는 어떻습니까?
가치 있는 앱을 만들기 위해 이 주제에 대한 깊은 이해가 필요하지 않을 수도 있지만, 저는 그 이유를 설명할 수 없이 기술 사이에서 선택하는 것을 좋아하지 않습니다.제 머리가 저한테 화가 나요.
질문 업데이트
모두에게 정보를 주셔서 감사합니다.몇 가지 명확한 질문은 다음과 같습니다.
- 코어 그래픽으로 무언가를 그리지만 UIImageViews와 사전 렌더링된 png로 동일한 작업을 수행할 수 있다면 항상 그 경로를 선택해야 합니까?
- 비슷한 질문입니다. 특히 이와 같은 불량 도구를 사용할 경우 코어 그래픽에서 인터페이스 요소를 그리는 것을 고려해야 합니까? (아마 요소의 디스플레이가 가변적인 경우, 예를 들어 20가지 색상의 버튼이 있습니다.)다른 사례는 없습니까?)
- 아래 답변에서 제가 이해한 바와 같이, 복잡한 UIView 렌더링 후 셀의 스냅샷 비트맵을 효과적으로 캡처하여 복잡한 보기를 스크롤하고 숨기면서 표시함으로써 테이블 셀에 대한 동일한 성능 향상을 얻을 수 있습니까?분명히 어떤 조각들은 해결되어야 할 것입니다.그냥 재미있는 생각이었어요.
가능할 때마다 UIKit 및 Subviews를 유지합니다.생산성을 높이고 유지보수가 용이한 모든 OOO 메커니즘을 활용할 수 있습니다.코어 그래픽은 UIKit에서 필요한 성능을 얻을 수 없거나 UIK에서 그림 효과를 함께 해킹하려고 하면 더 복잡해질 수 있습니다.
일반적인 워크플로우는 하위 뷰가 있는 테이블 뷰를 작성하는 것이어야 합니다.계측기를 사용하여 앱이 지원하는 가장 오래된 하드웨어의 프레임률을 측정합니다.60fps를 얻을 수 없는 경우 CoreGraphics로 드롭다운합니다.잠시 이 작업을 수행하면 UIK가 시간 낭비일 수 있다는 것을 알 수 있습니다.
그렇다면 코어 그래픽스가 빠른 이유는 무엇일까요?
CoreGraphics는 그다지 빠르지 않습니다.만약 그것이 항상 사용되고 있다면, 당신은 아마도 느리게 가고 있을 것입니다.GPU로 오프로드되는 많은 UIKit 작업과 달리 CPU에서 작업을 수행해야 하는 풍부한 그리기 API입니다.화면을 가로질러 움직이는 공을 애니메이션으로 만들어야 하는 경우 보기에서 setNeedsDisplay를 초당 60회 호출하는 것은 좋지 않은 생각입니다.따라서 개별적으로 애니메이션화해야 하는 뷰의 하위 구성요소가 있는 경우 각 구성요소는 별도의 레이어여야 합니다.
다른 문제는 drawRect로 사용자 지정 그리기를 수행하지 않을 때 UIK가 재고 뷰를 최적화하여 drawRect가 no-op이 되거나 컴포지팅으로 바로 가기를 취할 수 있다는 것입니다.drawRect를 오버라이드하면 UIK는 사용자가 무엇을 하고 있는지 전혀 모르기 때문에 느린 경로를 사용해야 합니다.
이 두 가지 문제는 테이블 뷰 셀의 경우 이점보다 클 수 있습니다.화면에 보기가 처음 나타나면 drawRect가 호출되고 내용이 캐시되며 스크롤은 GPU에서 수행하는 간단한 번역입니다.복잡한 계층 구조가 아닌 단일 뷰를 처리하기 때문에 UIKit의 그리기 최적화의 중요성이 줄어듭니다.따라서 병목 현상은 코어 그래픽 도면을 최적화할 수 있는 정도입니다.
가능할 때마다 UIKit을 사용합니다.작동하는 가장 간단한 구현을 수행합니다.프로필.인센티브가 있을 때 최적화합니다.
차이점은 UIView와 CALayer가 기본적으로 고정된 이미지를 다룬다는 것입니다.이러한 영상은 그래픽 카드에 업로드됩니다(OpenGL을 알고 있는 경우 영상을 텍스처로 생각하고 UIView/CALayer를 이러한 텍스처를 보여주는 다각형으로 생각합니다).일단 이미지가 GPU에 있으면 매우 빠르게 그리고 심지어 여러 번 그릴 수 있으며, 다른 이미지 위에 알파 투명도가 다양하더라도 (약간의 성능 저하가 있을 수 있습니다.
CoreGraphics/Quartz는 이미지 생성을 위한 API입니다.이것은 픽셀 버퍼(다시 말해 OpenGL 텍스처라고 생각합니다)를 사용하여 내부의 개별 픽셀을 변경합니다.이 모든 것은 RAM과 CPU에서 발생하며 Quartz가 완료된 후에만 이미지가 GPU로 "플래시"됩니다.GPU에서 이미지를 가져와 변경한 다음 전체 이미지(또는 적어도 비교적 큰 덩어리)를 GPU로 다시 업로드하는 이 왕복 작업은 다소 느립니다.또한 쿼츠가 실제로 그리는 그림은 여러분이 하는 것에 매우 빠르지만 GPU가 하는 것보다 훨씬 느립니다.
GPU가 대부분 큰 덩어리로 변경되지 않은 픽셀 주변을 이동한다는 것을 고려하면 그것은 명백합니다.Quartz는 픽셀의 랜덤 액세스를 수행하고 네트워킹, 오디오 등과 CPU를 공유합니다.또한 Quartz를 사용하여 동시에 그리는 여러 요소가 있으면 하나가 변경될 때 모두 다시 그린 다음 전체 청크를 업로드해야 하며, 하나의 이미지를 변경하여 UIViews 또는 CALayers가 다른 이미지에 붙여넣으면 훨씬 적은 양의 데이터를 GPU에 업로드하지 않아도 됩니다.
-drawRect:를 구현하지 않으면 대부분의 보기를 최적화할 수 있습니다.픽셀이 포함되어 있지 않기 때문에 아무것도 그릴 수 없습니다.UIImageView와 같은 다른 보기는 UIImage만 그립니다(이것도 본질적으로 텍스처에 대한 참조이며 이미 GPU에 로드되었을 수 있음).따라서 UIImageView를 사용하여 동일한 UIImage를 5회 그리면 GPU에 한 번만 업로드되고 5개의 다른 위치에 있는 디스플레이에 그려지므로 시간과 CPU가 절약됩니다.
-drawRect:를 구현하면 새 이미지가 생성됩니다.그런 다음 Quartz를 사용하여 CPU에 연결합니다.drawRect에 UI 이미지를 그린 경우 GPU에서 이미지를 다운로드하여 그릴 이미지로 복사한 후 이미지의 두 번째 복사본을 그래픽 카드에 다시 업로드합니다.즉, 장치에서 GPU 메모리의 두 배를 사용하는 것입니다.
따라서 가장 빠른 그리기 방법은 일반적으로 정적 콘텐츠를 변경되는 콘텐츠와 분리하여 표시하는 것입니다(별도의 UIView/UIView 하위 클래스/CALayers).정적 콘텐츠를 UI 이미지로 로드하고 UI 이미지 뷰를 사용하여 그린 다음 런타임에 동적으로 생성된 콘텐츠를 drawRect에 넣습니다.반복적으로 그려지는 콘텐츠가 있지만 자체적으로 변경되지 않는 경우(예: 일부 상태를 나타내기 위해 동일한 슬롯에 표시되는 3개의 아이콘) UIImageView도 사용합니다.
한 가지 주의 사항:UIV뷰가 너무 많은 것과 같은 것이 있습니다.특히 투명한 영역은 표시될 때 뒤에 있는 다른 픽셀과 혼합되어야 하기 때문에 그리기 위해 GPU에 더 큰 부담을 줍니다.이것이 바로 UIView를 "불투명"으로 표시하여 GPU에 해당 이미지 뒤에 있는 모든 것을 삭제할 수 있음을 나타낼 수 있는 이유입니다.
런타임에 동적으로 생성되지만 응용 프로그램의 수명 동안 동일하게 유지되는 콘텐츠(예: 사용자 이름이 포함된 레이블)가 있는 경우 텍스트, 버튼 테두리 등을 배경으로 Quartz를 사용하여 전체를 한 번 그리는 것이 실제로 의미가 있을 수 있습니다.그러나 이는 일반적으로 Instruments 앱이 다르게 알려주지 않는 한 필요하지 않은 최적화입니다.
저는 다른 사람들의 답변에서 제가 추론하고 있는 것에 대한 요약을 여기에 보관하고 원래 질문에 대한 업데이트에서 명확한 질문을 할 것입니다.하지만 저는 다른 사람들이 계속해서 답을 제시하고 좋은 정보를 제공한 사람들에게 투표할 것을 권장합니다.
일반 접근법
벤 샌도프스키가 답변에서 언급했듯이 일반적인 접근 방식은 "가능할 때마다 UIKit를 사용하십시오. 작동하는 가장 간단한 구현을 수행합니다. 프로필. 인센티브가 있을 때 최적화하십시오."
이유
- iDevice에는 CPU와 GPU라는 두 가지 주요 병목 현상이 있을 수 있습니다.
- CPU는 뷰의 초기 그리기/ 렌더링을 담당합니다.
- GPU는 애니메이션(코어 애니메이션), 레이어 효과, 컴포지팅 등의 대부분을 담당합니다.
- UIView에는 복잡한 뷰 계층을 처리하기 위한 다양한 최적화, 캐싱 등이 내장되어 있습니다.
- drawRect를 재정의할 때 UIView가 제공하는 많은 이점을 놓치게 되며, 일반적으로 렌더링을 UIView가 처리하도록 하는 것보다 속도가 느립니다.
하나의 평면 UIView에서 셀 내용을 그리면 스크롤 테이블의 FPS가 크게 향상될 수 있습니다.
위에서 말했듯이 CPU와 GPU는 두 가지 병목 현상이 될 수 있습니다.일반적으로 서로 다른 작업을 처리하기 때문에 어떤 병목 현상이 발생하는지 주의해야 합니다.스크롤링 테이블의 경우 코어 그래픽이 더 빨리 그려지는 것이 아니라 FPS를 크게 향상시킬 수 있는 이유입니다.
실제로 코어 그래픽은 초기 렌더의 중첩된 UIView 계층보다 훨씬 느릴 수 있습니다.하지만 화면 스크롤이 잘 안 되는 대표적인 이유는 GPU의 병목 현상이 발생하고 있기 때문에 이 문제를 해결해야 합니다.
drawRect(코어 그래픽 사용)를 재정의하면 테이블 스크롤에 도움이 되는 이유:
제가 알기로는 GPU는 뷰의 초기 렌더링을 담당하지 않고 렌더링 후 텍스처 또는 비트맵을 전달합니다.그런 다음 비트맵을 구성하고, 모든 레이어 영향을 렌더링하며, 애니메이션의 대부분을 담당합니다(코어 애니메이션).
테이블 뷰 셀의 경우 GPU는 하나의 비트맵을 애니메이션화하는 대신 상위 뷰를 애니메이션화하고 하위 뷰 레이아웃 계산, 레이어 효과 렌더링 및 모든 하위 뷰를 합성하기 때문에 복잡한 뷰 계층으로 병목 현상이 발생할 수 있습니다.따라서 하나의 비트맵을 애니메이션화하는 대신, 동일한 픽셀 영역에 대해 비트맵 다발의 관계와 상호 작용 방식을 담당합니다.
요약하자면, 코어 그래픽으로 한 뷰에 셀을 그리는 것이 테이블 스크롤 속도를 높일 수 있는 이유는 셀이 더 빨리 그려지기 때문이 아니라 GPU의 부하를 줄여주기 때문입니다. 이는 특정 시나리오에서 문제를 일으키는 병목 현상입니다.
저는 게임 개발자입니다. 제 친구가 UIImageView 기반 뷰 계층이 게임 속도를 저하시켜 게임을 엉망으로 만든다고 했을 때도 같은 질문을 하고 있었습니다.그리고 나서 저는 UIViews, CoreGraphics, OpenGL 또는 Cocos2D와 같은 타사 제품을 사용할지 여부에 대해 찾을 수 있는 모든 것을 조사했습니다.제가 WWDC의 친구들, 선생님들, 그리고 애플 엔지니어들로부터 받은 일관된 대답은 어느 정도는 그들 모두가 같은 일을 하고 있기 때문에 결국에는 큰 차이가 없을 것이라는 것이었습니다.UIViews와 같은 상위 레벨 옵션은 CoreGraphics와 OpenGL과 같은 하위 레벨 옵션에 의존합니다. 단지 코드로 감싸서 사용하기만 하면 됩니다.
UIView를 다시 작성하려는 경우 CoreGraphics를 사용하지 마십시오.그러나 모든 도면을 한 뷰에서 수행하는 한 CoreGraphics를 사용하면 어느 정도 속도를 낼 수 있습니다. 하지만 정말 그럴 만한 가치가 있을까요?제가 찾은 답은 대개 아니오입니다.제가 처음 게임을 시작했을 때, 저는 아이폰 3G로 일하고 있었습니다.게임의 복잡성이 증가함에 따라 약간의 지연이 발생하기 시작했지만, 최신 장치에서는 전혀 눈치채지 못했습니다.현재 저는 많은 작업을 진행하고 있으며, 아이폰 4에서 가장 복잡한 수준에서 재생할 때 1-3fps가 감소하는 것이 유일한 지연인 것 같습니다.
그래도 저는 Instruments를 사용하여 가장 많은 시간을 차지하는 기능을 찾기로 결정했습니다.저는 그 문제들이 제가 UIViews를 사용하는 것과 관련이 없다는 것을 발견했습니다.대신 특정 충돌 감지 계산을 위해 CGRectMake를 반복적으로 호출하고 동일한 이미지를 사용하는 특정 클래스에 대해 이미지 및 오디오 파일을 개별적으로 로드했습니다.
따라서 최종적으로 CoreGraphics를 사용하여 약간의 이득을 얻을 수는 있지만, 대개는 가치가 없거나 전혀 효과가 없을 수 있습니다.내가 코어그래픽을 사용하는 유일한 시간은 텍스트와 이미지가 아닌 기하학적 모양을 그릴 때입니다.
언급URL : https://stackoverflow.com/questions/14659563/to-drawrect-or-not-to-drawrect-when-should-one-use-drawrect-core-graphics-vs-su
'programing' 카테고리의 다른 글
| Exec : stdout "live" 표시 (0) | 2023.05.29 |
|---|---|
| 원격 서버의 Mongodump (0) | 2023.05.29 |
| Android용 Eclipse에서 ProGuard 사용 (0) | 2023.05.29 |
| Nodejs의 Mongodb vs Postgres (0) | 2023.05.29 |
| 선택한 쿼리의 출력을 하나의 어레이에 포스트그레스로 저장 (0) | 2023.05.29 |