iOS의 CGContext — 개념, 메서드 및 드로잉 컨텍스트 관리 방법

저자: IT Sectr 게시일: 2026-07-21 읽는 시간: 9 분

CGContext는 iOS 및 macOS에서 2D 드로잉 명령을 실행하기 위한 Core Graphics의 주요 객체입니다. 이는 현재 상태(채우기 색상, 선 두께, 변환, 클리핑 영역, 글꼴)를 저장하는 그래픽 컨텍스트를 나타냅니다. 선, 사각형, 텍스트, 이미지 등 모든 드로잉 작업은 CGContext를 통해 수행됩니다. Apple Developer Documentation, 2026에 따르면, CGContext는 Apple 생태계의 모든 래스터 및 벡터 그래픽의 기초입니다.

핵심 사항

  • CGContext는 모든 2D Core Graphics 명령이 실행되는 그래픽 컨텍스트입니다.
  • setStrokeColorsetFillColor는 컨텍스트에서 선과 채우기의 색상을 관리합니다.
  • addPathdrawPath는 임의의 CGPath 윤곽선을 그릴 수 있습니다.
  • clip(to:)은 드로잉을 특정 영역으로 제한하는 클리핑 영역을 설정합니다.
  • saveGStaterestoreGState는 컨텍스트 상태 스택을 저장하고 복원합니다.

CGContext란?

CGContext는 Core Graphics 프레임워크의 불투명 타입(opaque type)으로, 2D 렌더링 명령을 실행하기 위한 환경을 나타냅니다. 상태 스택, 현재 색상 공간, 좌표 변환 및 클리핑 영역을 관리합니다. CGContext는 모든 Quartz 2D 드로잉 함수가 상호 작용하는 유일한 객체이며, 모든 그래픽 작업은 이를 통해 이루어집니다.

CGContext는 목적에 따라 여러 변형이 있습니다: bitmap context는 메모리에서 래스터 이미지를 작업하기 위한 것, PDF context는 PDF 문서 생성을 위한 것, window context는 화면 드로잉을 위한 것(UIView가 draw(_:)에서 제공)입니다. iOS 개발자는 draw(_:) 메서드 내부의 UIGraphicsGetCurrentContext() 또는 오프라인 렌더링을 위한 UIGraphicsBeginImageContextWithOptions에서 얻은 컨텍스트를 가장 자주 사용합니다.

컨텍스트는 상태 스택을 통해 모든 설정을 적용합니다. 개발자는 현재 상태를 저장하고(saveGState), 매개변수를 수정하고, 이전 상태를 복원(restoreGState)할 수 있습니다. 이는 다른 요소에 다른 색상, 선 두께 및 변환이 필요한 복잡한 장면을 그릴 때 매우 중요합니다. Apple WWDC 2023에 따르면, 상태 스택의 올바른 사용은 코드 가독성을 향상시키고 시각적 아티팩트를 방지합니다.

상태 관리: saveGState와 restoreGState

CGContextSaveGState는 현재 컨텍스트 상태의 복사본을 스택에 푸시합니다. 이 상태에는 색상, 선 두께, 변환, 그림자, 클리핑 영역, 글꼴 등 모든 설정이 포함됩니다. 매개변수를 수정한 후 CGContextRestoreGState를 호출하면 컨텍스트가 저장된 상태로 돌아가 모든 중간 변경 사항이 취소됩니다. 스택은 iOS에서 최대 32개의 상태를 보유할 수 있습니다.

스택의 실제 사용

다른 스타일의 요소 그룹(예: 여러 색상의 차트 섹터)을 그릴 때 상태 스택은 각 매개변수를 수동으로 기억하고 복원할 필요를 없앱니다. saveGState/restoreGState가 없으면 개발자는 각 요소 후에 색상, 그림자 및 변환을 재설정해야 합니다. 스택 사용은 코드를 줄이고 복원 오류를 방지합니다.

저장과 복원의 균형을 유지하는 것이 중요합니다. 각 saveGState에는 일치하는 restoreGState가 있어야 합니다. 균형이 깨지면 상태 누수 또는 조기 복원이 발생하여 예측할 수 없는 렌더링이 발생합니다. Xcode의 정적 분석기는 CGContext 스택 균형을 확인하지 않으므로 정확성은 개발자의 책임입니다. do/finally 블록에서 쌍을 그룹화하는 것이 좋습니다.

swift
override func draw(_ rect: CGRect) {
    guard let ctx = UIGraphicsGetCurrentContext() else { return }

    ctx.saveGState()
    ctx.setStrokeColor(UIColor.red.cgColor)
    ctx.setLineWidth(3)
    ctx.addRect(CGRect(x: 50, y: 50, width: 200, height: 100))
    ctx.strokePath()
    ctx.restoreGState()
}

색상과 채우기

CGContextSetFillColorWithColor는 후속 작업의 채우기 색상을 설정합니다. 색상은 색상 공간 및 색상 구성 요소에 대한 정보를 포함하는 CGColorRef로 전달됩니다. CGContextSetStrokeColorWithColor는 선 색상에 대해 유사하게 작동합니다. Apple은 성능 향상을 위해 자주 사용되는 CGColorRef 값을 캐싱할 것을 권장합니다.

CGContext의 그라디언트

CGContextDrawLinearGradient는 지정된 색상으로 두 점 사이의 선형 그라디언트를 그립니다. CGContextDrawRadialGradient는 한 원에서 다른 원으로 전환되는 방사형 그라디언트를 만듭니다. 그라디언트로 작업하려면 먼저 색상 배열과 중지 위치를 포함하는 CGGradientRef 객체가 생성됩니다. CGContext의 그라디언트는 RGB 및 그레이스케일 색상 공간을 모두 지원합니다.

그라디언트로 영역을 채우려면 먼저 클리핑 영역을 설정해야 합니다. clip이 없으면 그라디언트는 원하는 모양뿐만 아니라 전체 컨텍스트를 채웁니다. 일반적인 패턴: 컨텍스트에 패스를 추가하고, 영역을 제한하기 위해 clip을 호출한 다음 그라디언트를 그립니다. 이 패턴은 버튼에서 배경에 이르기까지 복잡한 모양의 그라디언트 채우기가 필요한 모든 응용 프로그램에서 사용됩니다.

함수목적색상 공간
setFillColor채우기 색상 설정모두 (CGColor 통해)
setStrokeColor선 색상 설정모두 (CGColor 통해)
drawLinearGradient선형 그라디언트 그리기RGB 또는 그레이스케일
drawRadialGradient방사형 그라디언트 그리기RGB 또는 그레이스케일

패스와 선 그리기

CGContextAddPath는 이후 렌더링을 위해 이전에 생성된 CGPathRef를 컨텍스트에 추가합니다. 패스를 추가한 후에는 선(strokePath), 채우기(fillPath) 또는 둘 다 할 수 있습니다. CGContextBeginPath는 이전 패스를 지우고 새 패스를 시작합니다. 컨텍스트는 한 번에 하나의 활성 패스만 지원합니다.

점에 의한 직선과 곡선

CGContextMoveToPoint는 현재 윤곽선 점을 지정된 좌표로 이동합니다. CGContextAddLineToPoint는 현재 점에서 지정된 점까지 직선을 그립니다. CGContextAddCurveToPoint는 3차 베지어 곡선을 추가하고, CGContextAddQuadCurveToPoint는 2차 곡선을 추가합니다. CGContextClosePath는 마지막 점과 첫 번째 점 사이를 직선으로 연결하여 윤곽선을 닫습니다.

UIBezierPath에서는 이러한 모든 메서드가 패스 객체에서 호출되는 반면, CGContext에서는 컨텍스트에서 직접 호출됩니다. 이 차이점은 접근 방식을 선택할 때 중요합니다. UIBezierPath는 패스 재사용에 더 편리하고, CGContext는 최소 오버헤드로 일회성 드로잉에 더 적합합니다. CGContext는 또한 CGContextSetLineDash를 통한 점선, CGContextSetLineCap을 통한 유연한 끝, CGContextSetLineJoin을 통한 연결을 지원합니다.

swift
let ctx = UIGraphicsGetCurrentContext()!
ctx.beginPath()
ctx.moveTo(x: 50, y: 100)
ctx.addLineTo(x: 200, y: 100)
ctx.addCurveTo(x1: 250, y1: 50, x2: 300, y2: 150, x3: 350, y3: 100)
ctx.setStrokeColor(UIColor.blue.cgColor)
ctx.setLineWidth(5)
ctx.strokePath()

클리핑 영역과 변환

CGContextClip은 드로잉 영역을 현재 패스로 제한합니다. 이후의 모든 드로잉 작업은 이 영역 내에서만 표시됩니다. 이것은 마스킹, 모서리 둥글게 하기 및 사용자 정의 요소 경계 생성을 위한 기본 메커니즘입니다. 클리핑 영역은 saveGState/restoreGState를 통해 저장 및 복원됩니다.

좌표 변환

CGContextTranslateCTM은 컨텍스트 좌표계의 원점을 이동합니다. CGContextScaleCTM은 X 및 Y 축을 확대/축소합니다. CGContextRotateCTM은 현재 원점을 중심으로 좌표계를 회전합니다. 변환은 누적되며, 각 후속 변환은 현재 좌표계를 기준으로 적용됩니다. 복합 변환(이동 + 회전 + 확대/축소)은 애니메이션 및 요소 위치 지정에 사용됩니다.

클리핑과 변환의 결합은 강력한 기능을 제공합니다. 클리핑을 통해 복잡한 마스크를 그린 다음 전체 콘텐츠에 변환을 적용할 수 있습니다. 일반적인 예는 둥근 모서리와 함께 각도가 있는 이미지 부분을 표시하는 것입니다. 작업 순서가 중요합니다. 먼저 클리핑 영역을 설정하고, 그런 다음 변환을 적용하고, 그 다음 콘텐츠를 그립니다. Apple은 드로잉 루프에서 CTM(현재 변환 행렬) 변경을 최소화할 것을 권장합니다.

swift
override func draw(_ rect: CGRect) {
    guard let ctx = UIGraphicsGetCurrentContext() else { return }
    ctx.saveGState()

    // clipping region - circle
    ctx.addEllipse(in: CGRect(x: 50, y: 50, width: 200, height: 200))
    ctx.clip()

    // content transformation
    ctx.translateBy(x: 150, y: 150)
    ctx.rotate(by: .pi / 4)
    ctx.translateBy(x: -150, y: -150)

    UIImage(named: "photo")?.draw(at: CGPoint(x: 50, y: 50))
    ctx.restoreGState()
}

CGContext 드로잉 예제

CGContext를 사용하여 그라디언트 차트를 만드는 전체 예제를 살펴보겠습니다. 차트에는 그라디언트 채우기와 텍스트 레이블이 있는 세 가지 다른 색상의 섹터가 포함됩니다. 이 코드는 단일 컨텍스트에서 saveGState, clip, 그라디언트 및 텍스트 렌더링의 조합을 보여줍니다.

swift
class PieChartView: UIView {

    private struct Slice {
        let color: UIColor
        let value: CGFloat
        let label: String
    }

    override func draw(_ rect: CGRect) {
        guard let ctx = UIGraphicsGetCurrentContext() else { return }

        let slices = [
            Slice(color: .systemRed, value: 0.4, label: "iOS"),
            Slice(color: .systemGreen, value: 0.35, label: "Android"),
            Slice(color: .systemBlue, value: 0.25, label: "Other")
        ]

        let center = CGPoint(x: bounds.midX, y: bounds.midY)
        let radius = bounds.width * 0.35
        var startAngle: CGFloat = -.pi / 2

        for slice in slices {
            let endAngle = startAngle + .pi * 2 * slice.value

            ctx.saveGState()
            ctx.moveTo(x: center.x, y: center.y)
            ctx.addArc(center: center, radius: radius,
                       startAngle: startAngle, endAngle: endAngle, clockwise: false)
            ctx.closePath()
            ctx.setFillColor(slice.color.cgColor)
            ctx.fillPath()

            // text label
            let midAngle = startAngle + endAngle / 2
            let labelPos = CGPoint(
                x: center.x + radius * 0.7 * cos(midAngle),
                y: center.y + radius * 0.7 * sin(midAngle)
            )
            slice.label.draw(at: labelPos, withAttributes: [
                .foregroundColor: UIColor.white,
                .font: UIFont.boldSystemFont(ofSize: 14)
            ])
            ctx.restoreGState()
            startAngle = endAngle
        }
    }
}

이 예제에서 차트의 각 섹터는 자체 saveGState/restoreGState 블록에서 그려집니다. 이 접근 방식은 한 섹터의 색상 및 패스 설정이 다른 섹터에 영향을 미치지 않도록 보장합니다. addArc 메서드는 시작 각도에서 끝 각도까지 호를 만들고, closePath는 섹터를 중심 방향으로 닫습니다. 레이블 텍스트는 삼각 함수 cos과 sin을 사용하여 위치를 계산하여 섹터의 중간 각도에 배치됩니다.

빈번한 다시 그리기 중 성능을 향상시키려면 각도 및 위치 계산을 별도 배열에 캐싱하는 것이 좋습니다. CGContext는 모든 작업을 CPU에서 실행하므로 수십 개의 섹터가 있는 복잡한 장면은 최적화가 필요할 수 있습니다(예: CGLayer에서 사전 렌더링 또는 GPU 가속을 위한 Metal 사용). 5–10개 요소의 대부분 UI 작업에서는 CGContext 성능이 허용 가능한 수준으로 유지됩니다.

자주 묻는 질문

iOS에서 현재 CGContext를 얻는 방법은?

UIView의 draw(_:) 메서드 내부 또는 UIGraphicsBeginImageContextWithOptions 블록 내부에서 UIGraphicsGetCurrentContext()를 호출합니다. CALayer 레이어의 경우 CALayerDelegate의 draw(in:) 메서드를 사용하면 준비된 컨텍스트를 받을 수 있습니다.

fillPath와 strokePath의 차이점은?

fillPath는 현재 패스의 내부를 setFillColor의 색상으로 채웁니다. strokePath는 setStrokeColor, setLineWidth 및 setLineCap의 매개변수로 패스를 따라 선을 그립니다. 두 작업은 순차적으로 수행됩니다: 먼저 채우기, 그런 다음 필요한 경우 선.

비트맵 CGContext란?

Bitmap CGContext는 CGBitmapContextCreate를 통해 생성된 컨텍스트로, 화면 대신 메모리 버퍼에 그립니다. 백그라운드 이미지 생성, 표시 없는 그래픽 처리 및 Metal 또는 OpenGL용 텍스처 생성에 사용됩니다.

모든 CGContext 설정을 재설정하는 방법은?

Core Graphics는 모든 설정을 재설정하는 메서드를 제공하지 않습니다. 변경 전에 saveGState를 사용하고 원래 상태로 돌아가려면 restoreGState를 사용합니다. 또는 동일한 매개변수로 새 컨텍스트를 만듭니다.

도형 내부에 그라디언트가 표시되지 않는 이유는?

drawLinearGradient를 호출하기 전에 원하는 패스에서 clip을 통해 클리핑 영역을 설정합니다. clip이 없으면 그라디언트가 전체 컨텍스트를 채웁니다. 순서: addPath → clip → drawLinearGradient — 도형 내부에 그라디언트가 보장됩니다.

요약

  • CGContext는 iOS 및 macOS의 모든 2D 드로잉 작업을 위한 Core Graphics의 중앙 객체입니다.
  • saveGStaterestoreGState는 컨텍스트 상태 스택을 관리하여 부작용을 방지합니다.
  • setFillColorsetStrokeColor는 CGColorRef를 통해 채우기 및 선 색상을 설정합니다.
  • addPath, strokePath, fillPath는 임의의 CGPath 윤곽선으로 작업합니다.
  • clip은 마스크 및 둥글게 하기를 위해 드로잉 영역을 현재 패스로 제한합니다.
  • translateCTM, scaleCTM, rotateCTM은 컨텍스트 좌표계를 변환합니다.
  • 모든 CGContext 작업은 CPU에서 실행됩니다. 복잡한 그래픽의 경우 CGLayer 또는 Metal을 사용하세요.

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기