CGContext in iOS — what it is, methods and how to manage the drawing context

Author: IT Sectr Published: 2026-07-21 Reading time: 9 min

CGContext is the primary Core Graphics object for executing 2D drawing commands in iOS and macOS. It represents a graphics context that stores the current state: fill color, line thickness, transformation, clipping area, and fonts. All drawing operations — lines, rectangles, text, images — are performed through CGContext. According to Apple Developer Documentation, 2026, CGContext is the foundation of all raster and vector graphics in the Apple ecosystem.

Key Takeaways

  • CGContext is the graphics context through which all 2D Core Graphics commands are executed.
  • setStrokeColor and setFillColor manage the color of lines and fills in the context.
  • addPath and drawPath allow drawing arbitrary CGPath contours.
  • clip(to:) sets the clipping area to restrict drawing to a specific zone.
  • saveGState and restoreGState save and restore the context state stack.

What is CGContext?

CGContext is an opaque type from the Core Graphics framework that represents an environment for executing 2D rendering commands. It manages the state stack, current color space, coordinate transformation, and clipping area. CGContext is the only object that all Quartz 2D drawing functions interact with — any graphics operation passes through it.

CGContext comes in several varieties depending on its purpose: bitmap context for working with raster images in memory, PDF context for generating PDF documents, window context for on-screen drawing (provided by UIView in draw(_:)). iOS developers most often work with a context obtained from UIGraphicsGetCurrentContext() inside the draw(_:) method or from UIGraphicsBeginImageContextWithOptions for offline rendering.

The context applies all settings through a state stack — the developer can save the current state (saveGState), modify parameters, and restore the previous state (restoreGState). This is critically important when drawing complex scenes where different elements require different colors, line thicknesses, and transformations. According to Apple WWDC 2023, proper use of the state stack improves code readability and prevents visual artifacts.

State Management: saveGState and restoreGState

CGContextSaveGState pushes a copy of the current context state onto the stack. This state includes all settings: colors, line thickness, transformation, shadows, clipping area, fonts. After modifying parameters, calling CGContextRestoreGState returns the context to the saved state, undoing all intermediate changes. The stack can hold up to 32 states on iOS.

Practical Use of the Stack

When drawing groups of elements with different styles (e.g., multi-colored chart sectors), the state stack eliminates the need to manually remember and restore each parameter. Without saveGState/restoreGState, the developer would have to reset the color, shadow, and transformation after each element. Using the stack reduces code and prevents restoration errors.

It is important to maintain a balance of saves and restores — each saveGState must have a matching restoreGState. Breaking the balance leads to state leaks or premature restoration, causing unpredictable rendering. Xcode's static analyzer does not check CGContext stack balance, so correctness is the developer's responsibility. It is recommended to group pairs in do/finally blocks.

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()
}

Colors and Fills

CGContextSetFillColorWithColor sets the fill color for subsequent operations. The color is passed as CGColorRef, which contains information about the color space and color components. CGContextSetStrokeColorWithColor works similarly for stroke color. Apple recommends caching frequently used CGColorRef values for better performance.

Gradients in CGContext

CGContextDrawLinearGradient draws a linear gradient between two points with specified colors. CGContextDrawRadialGradient creates a radial gradient transitioning from one circle to another. To work with gradients, a CGGradientRef object is first created containing an array of colors and stop positions. Gradients in CGContext support both RGB and Grayscale color spaces.

Filling an area with a gradient requires setting up a clipping area first. Without clip, the gradient will fill the entire context, not just the desired shape. The typical pattern: add a path to the context, call clip to restrict the area, then draw the gradient. This pattern is used in all applications that require gradient fills of complex shapes, from buttons to backgrounds.

FunctionPurposeColor Space
setFillColorSets the fill colorAny (via CGColor)
setStrokeColorSets the stroke colorAny (via CGColor)
drawLinearGradientDraws a linear gradientRGB or Grayscale
drawRadialGradientDraws a radial gradientRGB or Grayscale

Drawing Paths and Lines

CGContextAddPath adds a previously created CGPathRef to the context for subsequent rendering. After adding a path, it can be stroked (strokePath), filled (fillPath), or both. CGContextBeginPath starts a new path, clearing the previous one. The context supports only one active path at a time.

Straight Lines and Curves by Points

CGContextMoveToPoint moves the current contour point to the specified coordinates. CGContextAddLineToPoint draws a straight line from the current point to the given point. CGContextAddCurveToPoint adds a cubic Bezier curve, CGContextAddQuadCurveToPoint adds a quadratic one. CGContextClosePath closes the contour with a straight line between the last and first point.

Unlike UIBezierPath, where all these methods are called on the path object, in CGContext they are called directly on the context. This difference matters when choosing an approach: UIBezierPath is more convenient for reusing paths, CGContext is better for one-time drawing with minimal overhead. CGContext also supports dashed lines via CGContextSetLineDash, flexible line caps via CGContextSetLineCap, and joins via 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()

Clipping Area and Transformations

CGContextClip restricts the drawing area to the current path. All subsequent drawing operations will be visible only within this area. This is the basic mechanism for masking, rounding corners, and creating custom element boundaries. The clipping area is also saved and restored via saveGState/restoreGState.

Coordinate Transformations

CGContextTranslateCTM shifts the origin of the context coordinate system. CGContextScaleCTM scales the X and Y axes. CGContextRotateCTM rotates the coordinate system around the current origin. Transformations accumulate — each subsequent one is applied relative to the current coordinate system. Composite transformations (translation + rotation + scaling) are used for animation and element positioning.

Combining clipping and transformations provides powerful capabilities: you can draw a complex mask through clipping, then apply a transformation to the entire content. A typical example is displaying part of an image at an angle with rounded corners. Operation order matters: first set the clipping area, then apply the transformation, then draw the content. Apple recommends minimizing CTM (Current Transformation Matrix) changes in the drawing loop.

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()
}

Drawing Example in CGContext

Let's look at a complete example of creating a gradient chart using CGContext. The chart includes three sectors of different colors with gradient fills and text labels. The code demonstrates the combination of saveGState, clip, gradients, and text rendering in a single context.

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
        }
    }
}

In this example, each chart sector is drawn in its own saveGState/restoreGState block. This approach guarantees that color and path settings for one sector do not affect others. The addArc method creates an arc from the start to the end angle, and closePath closes the sector to the center. The label text is placed at the midpoint angle of the sector using trigonometric functions cos and sin for position calculation.

To improve performance during frequent redrawing, it is recommended to cache angle and position calculations in a separate array. CGContext executes all operations on the CPU, so complex scenes with dozens of sectors may require optimization — for example, pre-rendering in CGLayer or using Metal for GPU acceleration. For most UI tasks with 5–10 elements, CGContext performance remains acceptable.

Frequently Asked Questions

How to get the current CGContext in iOS?

Call UIGraphicsGetCurrentContext() inside the draw(_:) method of UIView or inside a UIGraphicsBeginImageContextWithOptions block. For CALayer layers, use the draw(in:) method of CALayerDelegate, which receives a ready-made context.

What is the difference between fillPath and strokePath?

fillPath fills the interior of the current path with the color from setFillColor. strokePath draws a line along the path with the parameters from setStrokeColor, setLineWidth, and setLineCap. Both operations are performed sequentially: first fill, then stroke if needed.

What is a bitmap CGContext?

Bitmap CGContext is a context created via CGBitmapContextCreate that draws into a memory buffer instead of the screen. It is used for background image generation, graphics processing without display, and creating textures for Metal or OpenGL.

How to reset all CGContext settings?

Core Graphics does not provide a method to reset all settings. Use saveGState before changes and restoreGState to return to the original state. Alternatively, create a new context with the same parameters.

Why is the gradient not displaying inside the shape?

Before calling drawLinearGradient, set the clipping area via clip on the desired path. Without clip, the gradient fills the entire context. Order: addPath → clip → drawLinearGradient — guarantees the gradient inside the shape.

Summary

  • CGContext is the central Core Graphics object for all 2D drawing operations on iOS and macOS.
  • saveGState and restoreGState manage the context state stack, preventing side effects.
  • setFillColor and setStrokeColor set fill and stroke colors via CGColorRef.
  • addPath, strokePath, fillPath work with arbitrary CGPath contours.
  • clip restricts the drawing area to the current path for masks and rounding.
  • translateCTM, scaleCTM, rotateCTM transform the context coordinate system.
  • All CGContext operations run on the CPU — for complex graphics use CGLayer or Metal.

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also