기어가더라도 제대로

[SwiftUI-기초] drawingGroup() - Image 성능 높이기 본문

SwiftUI - 기초

[SwiftUI-기초] drawingGroup() - Image 성능 높이기

Damagucci-juice 2022. 11. 18. 22:10
  • 다소 자극적인 제목을 달아놨는데, 성능을 높이는 원리를 말씀드림
  • 기본적으로 뷰 렌더링 작업은 Core Animation 을 사용
  • 다만 그리기 작업이 좀 복잡해지면 화면이 일정 FPS 아래로 내려가는 것을 볼 수 있음
  • iOS 최대 주사율은 120 fps 인데 복잡한 그리기 작업이 들어가면 그 이하로도 내려갈 수 있음
  • 예제 코드를 통해서 알아보겠음
struct ContentView: View {
    @State private var colorCycle = 0.0

    var body: some View {
        VStack {
            ColorCyclingCircle(amount: colorCycle)
                .frame(width: 300, height: 300)

            Slider(value: $colorCycle)
        }
    }
}

struct ColorCyclingCircle: View {
    var amount = 0.0
    var steps = 100

    var body: some View {
        ZStack {
            ForEach(0..<steps) { value in
                Circle()
                    .inset(by: Double(value))
                    .strokeBorder(color(for: value, brightness: 1), lineWidth: 2)
            }
        }
    }

    func color(for value: Int, brightness: Double) -> Color {
        var targetHue = Double(value) / Double(steps) + amount

        if targetHue > 1 {
            targetHue -= 1
        }

        return Color(hue: targetHue, saturation: 1, brightness: brightness)
    }
}
  • 코드가 어렵긴한데 100개의 원을 그리는 뷰
  • 100개의 원을 각각 100개의 뷰로 그려냄
  • 이미 복잡한데 아직 그렇게 느리지는 않음
  • 의도적으로 복잡도를 높이기 위해 기존에 컬러 대신 선형 그라디언트를 추가

.strokeBorder(
    LinearGradient(
        gradient: Gradient(colors: [
            color(for: value, brightness: 1),
            color(for: value, brightness: 0.5)
        ]), 
        startPoint: .top,
        endPoint: .bottom
    ), 
    lineWidth: 2
)
  • 위에서 아래로 갈수록 밝기를 절반정도 줄인 선형 그라데이션을 추가했는데 극적으로 느려짐
  • 슬라이더를 움직이기 어려운 정도

.drawingGroup

  • 위의 코드는 복잡하지만 100의 원을 그리기 위해 100개의 View를 그려냈다고 하면..
  • drawingGroup() 을 통해서 하나의 통합된 뷰로 나타낼 수 있다면 많은 계산 과정이 줄어듦
  • 일반적인 뷰렌더링은 Core Animation 이지만 .drawingGroup()은 Metal 을 사용
  • Metal: GPU를 이용하여 그리기에 더 전문적인 프레임워크
  • 결과적으로 100개의 view 가 아닌 통합으로 렌더링된 하나의 view 가 나옴
  • 컨텐츠를 렌더링해서 하나 하나의 뷰를 내는 것이 아니라 화면에서 뷰로 나오기 전에 스크린의 이미지로 뷰를 합쳐서 하나의 뷰로 나옴
  • 결과적으로 화면 그리기 작업이 빨라짐
// ColorCyclingCircle

var body: some View {
    ZStack {
        // existing code…
    }
    .drawingGroup()
}
  • Metal은 꼭 필요한 때에만 사용해야함
  • 닭 잡는데 소잡는 칼 필요 없듯이 간단한 뷰를 그릴 때조차 GPU를 사용하기에 과도한 자원 소모가 될 수 있음
Comments