Generating PDF Reports in Swift for iOS and macOS with PDFKit and Core Graphics

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Generating PDF Reports in Swift for iOS and macOS



Creating PDF documents is a common task in mobile and desktop applications. On Apple platforms (iOS, macOS), powerful built-in tools are available for this: PDFKit and Core Graphics. In this article, we will walk through how to generate a multi-page report with tables, text, and graphics using only native Swift.



Why Use Built-in Tools?

  • No third-party dependencies required — everything is already included in the SDK.
  • Full control over rendering — work with coordinates, fonts, and colors.
  • Cross-platform — the code works on both iOS and macOS.
  • High performance — Core Graphics uses hardware acceleration.


Main Approaches

There are two main ways to generate PDFs in Swift:

  1. PDFKit — a high-level API for working with PDFs (reading, editing, creating).
  2. Core Graphics — low-level rendering via a PDF context.

We will look at the second approach, as it provides maximum flexibility when creating reports "from scratch."



Creating a PDF Context

The first step is to create a PDF context into which we will draw elements. The function UIGraphicsBeginPDFContextToFile (iOS) or its macOS equivalent is used for this.



import UIKit

func generatePDF() -> URL? { let fileName = "Report.pdf" let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) guard let documentsURL = paths.first else { return nil } let pdfURL = documentsURL.appendingPathComponent(fileName) let pageSize = CGRect(x: 0, y: 0, width: 612, height: 792) // A4 UIGraphicsBeginPDFContextToFile(pdfURL.path, pageSize, nil) // We will draw pages here UIGraphicsEndPDFContext() return pdfURL}


Adding Pages and Content

Each page begins with a call to UIGraphicsBeginPDFPage(). After that, standard UIKit drawing methods can be used.



func drawReport() {    guard let pdfURL = generatePDF() else { return }        UIGraphicsBeginPDFContextToFile(pdfURL.path, CGRect(x: 0, y: 0, width: 612, height: 792), nil)        // First page    UIGraphicsBeginPDFPage()    drawHeader(title: "Monthly Report")    drawTable(data: sampleData)        // Second page (if needed)    UIGraphicsBeginPDFPage()    drawChart()        UIGraphicsEndPDFContext()}


Drawing Text and Headers

To draw text, we use NSString with attributes.



func drawHeader(title: String) {    let titleAttributes: [NSAttributedString.Key: Any] = [        .font: UIFont.boldSystemFont(ofSize: 24),        .foregroundColor: UIColor.darkGray    ]    title.draw(at: CGPoint(x: 50, y: 40), withAttributes: titleAttributes)}


Creating a Simple Table

A table can be drawn using lines and text. Below is an example of generating a table with two columns.



func drawTable(data: [(String, String)]) {    let startX: CGFloat = 50    var startY: CGFloat = 100    let colWidth: CGFloat = 250    let rowHeight: CGFloat = 30        // Draw headers    let headerAttributes: [NSAttributedString.Key: Any] = [        .font: UIFont.boldSystemFont(ofSize: 14),        .foregroundColor: UIColor.black    ]    "Name".draw(at: CGPoint(x: startX, y: startY), withAttributes: headerAttributes)    "Value".draw(at: CGPoint(x: startX + colWidth, y: startY), withAttributes: headerAttributes)        startY += rowHeight        // Draw rows    for (key, value) in data {        let rowAtt                    

Recommendations