Generating PDF Reports in Swift: PDFKit and UIPrintPageRenderer

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 (iOS/macOS) Using PDFKit



Creating PDF documents is a common task in mobile and desktop applications. On Apple platforms (iOS, macOS, watchOS, tvOS), the built-in framework PDFKit is used for this purpose. It allows you to programmatically generate, display, and edit PDF files. In this article, we will explore how to create a full-fledged PDF report using Swift: with text, tables, images, and customizable pages.



What is PDFKit?

PDFKit is an Apple framework included in the standard iOS/macOS SDKs. It provides classes for working with PDF:

  • PDFDocument — representation of the entire document.
  • PDFPage — an individual page.
  • PDFView — displaying PDF on screen.
  • UIPrintPageRenderer (for iOS) — page generation via Core Graphics drawing.

For report generation, UIPrintPageRenderer is most commonly used, or you can draw directly via Core Graphics in a PDF context. The second method offers more flexibility but requires more code.



Project Setup

Open Xcode, create a new project for iOS or macOS. Make sure to import the PDFKit module:

import PDFKitimport UIKit // for iOS


For macOS, you will need import Cocoa and corresponding work with NSView.



Method 1: Generating PDF via UIPrintPageRenderer (iOS)

This method is convenient if you want to use HTML markup or complex layouts. UIPrintPageRenderer allows you to render pages using UIPrintFormatter.



func generatePDFUsingRenderer() -> Data? {    let renderer = UIPrintPageRenderer()        // Setting up A4 page size    let pageSize = CGRect(x: 0, y: 0, width: 595.2, height: 841.8) // in points    renderer.setValue(pageSize, forKey: "paperRect")    renderer.setValue(pageSize, forKey: "printableRect")        // Creating an HTML string with the report    let htmlString = """    <h1>Sales Report</h1>    <p>Date: 2025-03-17</p>    <table border="1">        <tr><th>Product</th><th>Quantity</th><th>Price</th></tr>        <tr><td>Laptop</td><td>5</td><td>50000</td></tr>        <tr><td>Mouse</td><td>20</td><td>1500</td></tr>    </table>    """        let formatter = UIMarkupTextPrintFormatter(markupText: htmlString)    renderer.addPrintFormatter(formatter, startingAtPageAt: 0)        // Rendering to PDF    let pdfData = NSMutableData()    UIGraphicsBeginPDFContextToData(pdfData, .zero, nil)        for pageIndex in 0..<renderer.numberOfPages {        UIGraphicsBeginPDFPage()        renderer.drawPage(at: pageIndex, in: UIGraphicsGetCurrentContext()!)    }        UIGraphicsEndPDFContext()    return pdfData as Data}


Call the function and save the result:

if let pdfData = generatePDFUsingRenderer() {    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)    let fileURL = paths[0].appendingPathComponent("report.pdf")    try? pdfData.write(to: fileURL)    print("PDF saved: \\(fileURL)")}


Method 2: Drawing via Core Graphics (iOS/macOS)

This method is more low-level but gives you full control over every element. It is suitable for macOS, where UIPrintPageRenderer is not available.



func generatePDFWithCoreGraphics() -> Data? {    let pdfData = NSMutableData()    let pageRect = CGRect(x: 0, y: 0, width: 612, height: 792) // US Letter        guard let consumer = CGDataConsumer(data: pdfData),          let pdfContext = CGContext(consumer: consu                    

Recommendations