SwiftUI 렌더링
낯선 언어를 매일 학습하며 몰입과 성장을 기록하는 일지
· 2 min read
문제 상황 #
- UI에 blur 및 gradient 적용 시 버벅임 발생
- UX에 매우 큰 영향 발생
- SwiftUI의 작동 방식에 대한 학습 필요
SwiftUI 렌더링 파이프라인 #
- SwiftUI는 벡터 방식이 기본
기본 파이프 라인 #
- 레이아웃: 위치 잡기
- 그리기(CPU): View Hierarchy의 모든 요소(Circle, Shadow, Text)를 개별 레이어로 취급, 레이어를 얹어가면서 취합
- 디스플레이: 모두 합쳐서 화면에 보여줌
graph TD
User[👆 User Scroll Action] -->|1. Trigger Redraw| ViewHierarchy
subgraph ViewHierarchy [SwiftUI View Layer]
direction TB
Ball[Circle View]
Shadow[Effect: Shadow]
Blur[Effect: Blur]
Text[Text View]
end
ViewHierarchy -->|2. Calculate Layout & Effects| CPU
subgraph CPU_Process [🔥 CPU: Main Thread]
Calc1[Rasterize Vector Path]
Calc2[Compute Blur Radius]
Calc3[Composite Layers]
end
CPU_Process -->|3. Heavy Load| GPU[⚠️ GPU: Laggy Display]
%% 스타일링: 붉은색 계열로 부하 강조
style CPU_Process fill:#ffcccc,stroke:#d32f2f,stroke-width:2px
style GPU fill:#ffebee,stroke:#d32f2f,stroke-width:2px,stroke-dasharray: 5 5
style ViewHierarchy fill:#fff3e0,stroke:#ff9800,stroke-width:1px
문제 원인 #
- 스크롤을 할 때마다 실시간으로 레이어들을 모두 다시 그림
- Shodow, blur와 같은 복잡한 연산은 높은 CPU 점유율을 발생시킴
해결 방법 #
.drawingGroup()을 통해 파이프라인 변경(Flattening)
변경된 파이프라인 #
- Off-Screen Rendering
- 백그라운드에서 모든 효과를 합쳐 한 장의 이미지(비트맵)으로 만듦
- 레이어를 모두 겹쳐 캡처하여 JPG 파일로 만드는 것과 비슷
- GPU Handover
- 만들어진 이미지를 GPU에 전달
- GPU는 이미지 연산은 매우 빠름
- Display
- 스크롤 시 CPU는 연산하지 않고 GPU가 이미지만 옮김
graph TD
Init[🚀 Initial Load] -->|1. Apply .drawingGroup| Metal
subgraph OffScreen [Off-screen Rendering]
Metal[⚙️ Metal Engine] -->|Flattening| Bitmap[🖼️ Single Bitmap / Texture]
end
Bitmap -->|2. Cache Result| GPUMemory[💾 GPU Memory]
User[👆 User Scroll Action] -->|3. Zero Calculation| GPU
subgraph GPU_Process [🚀 GPU: Render Server]
GPUMemory -->|Simply Move Coordinates| Display[✨ Smooth 120Hz Display]
end
%% 스타일링: 초록/파란색 계열로 최적화 강조
style OffScreen fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
style GPU_Process fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
style Bitmap fill:#fffde7,stroke:#fbc02d,stroke-width:2px
style Display fill:#00c853,stroke:#00695c,stroke-width:2px,color:white
Trade-off #
.drawingGroup() 사용 시
#
- RAM 사용량 증가
- 벡터는 수식이 작지만, 비트맵은 용량이 큼
- 화질 저하 가능성 있음
- 확대 시 화질 깨질 수 있음
따라서 단순 텍스트나 버튼엔 사용하지 않는 것이 유리하고, 그림자나 그라데이션이 들어간 복잡한 뷰의 경우 사용이 권장된다.
배운 점과 인사이트 #
- Swift 문법/프레임워크에서 새롭게 이해한 부분
- 기존 언어/경험과 비교했을 때의 차이점