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 iOSFor 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 Also in library
Sending SMS in Java: Overview and Examples of Using API Libraries (Twilio, Nexmo)
Task Queues in Rust: Overview of Libraries for Asynchronous Processing
Cryptography in TypeScript: Encryption and Hashing in Practice
GraphQL in Go: Complete Guide to the gqlgen Library
Caching in Rust: Redis, Memcached, and Built-in Solutions