{"id":233,"date":"2017-02-13T04:56:29","date_gmt":"2017-02-13T04:56:29","guid":{"rendered":"http:\/\/inwizards.com\/blog\/?p=233"},"modified":"2026-01-02T14:04:30","modified_gmt":"2026-01-02T14:04:30","slug":"convert-text-content-pdf-file-swift-2-0","status":"publish","type":"post","link":"https:\/\/www.inwizards.com\/blog\/convert-text-content-pdf-file-swift-2-0\/","title":{"rendered":"How to Convert Text Content into a PDF File in Swift (iOS \u2013 Swift 5+)"},"content":{"rendered":"<p>Creating PDF files dynamically in an iOS application is a common requirement for features like invoices, reports, user-generated documents, or downloadable content. In this guide, you\u2019ll learn <b>how to convert text content into a PDF file in Swift using modern iOS APIs (Swift 5+)<\/b>.<\/p>\n<p>This tutorial demonstrates how to:<\/p>\n<ul>\n<li aria-level=\"1\">Generate a PDF file programmatically<\/li>\n<li aria-level=\"1\">Render text content inside a PDF<\/li>\n<li aria-level=\"1\">Save the PDF locally on the device<\/li>\n<li aria-level=\"1\">Access the generated PDF for sharing or preview<\/li>\n<\/ul>\n<h2><b>Why Generate PDFs in an iOS App?<\/b><\/h2>\n<p>PDF generation is useful for many real-world scenarios, including:<\/p>\n<ul>\n<li aria-level=\"1\">Exporting reports or analytics<\/li>\n<li aria-level=\"1\">Generating invoices or receipts<\/li>\n<li aria-level=\"1\">Saving form data as documents<\/li>\n<li aria-level=\"1\">Sharing user-generated content<\/li>\n<li aria-level=\"1\">Offline document storage<\/li>\n<\/ul>\n<p>iOS provides powerful native APIs that allow you to generate PDFs <b>without third-party libraries<\/b>, ensuring better performance and long-term stability.<\/p>\n<h3><b>Prerequisites<\/b><\/h3>\n<p>Before you start, make sure you have:<\/p>\n<ul>\n<li aria-level=\"1\">Xcode 14 or later<\/li>\n<li aria-level=\"1\">Swift 5+<\/li>\n<li aria-level=\"1\">Basic knowledge of UIKit<\/li>\n<li aria-level=\"1\">An iOS project using UIKit (not SwiftUI)<\/li>\n<\/ul>\n<h3><b>Project Setup<\/b><\/h3>\n<ol>\n<li aria-level=\"1\">Open <b>Xcode<\/b> and create a new <b>Single View App<\/b><b>\n<p><\/b><\/li>\n<li aria-level=\"1\">Choose <b>UIKit<\/b> and <b>Swift<\/b><b>\n<p><\/b><\/li>\n<li aria-level=\"1\">Name the project GeneratePDFDemo<\/li>\n<\/ol>\n<h3><b>UI Elements<\/b><\/h3>\n<p>Add the following to your storyboard:<\/p>\n<ul>\n<li aria-level=\"1\">A UITextView (for user input)<\/li>\n<li aria-level=\"1\">A UIButton labeled <b>\u201cGenerate PDF\u201d<\/b><b>\n<p><\/b><\/li>\n<\/ul>\n<p>Connect:<\/p>\n<ul>\n<li aria-level=\"1\">UITextView \u2192 IBOutlet (textView)<\/li>\n<li aria-level=\"1\">UIButton \u2192 IBAction (generatePDF)<\/li>\n<\/ul>\n<h3><b>Modern Way to Create PDFs in Swift<\/b><\/h3>\n<p>Starting with iOS 10, Apple introduced <b>UIGraphicsPDFRenderer<\/b>, which is the recommended way to create PDFs.<\/p>\n<h4><b>Why Use UIGraphicsPDFRenderer?<\/b><\/h4>\n<ul>\n<li aria-level=\"1\">Better performance<\/li>\n<li aria-level=\"1\">Cleaner API<\/li>\n<li aria-level=\"1\">Supports modern Swift<\/li>\n<li aria-level=\"1\">Automatically manages PDF contexts<\/li>\n<\/ul>\n<h4><b>Step 1: Create the PDF File URL<\/b><\/h4>\n<p>func getDocumentsDirectory() -&gt; URL {<\/p>\n<p>FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>This ensures the PDF is stored safely inside the app\u2019s sandbox.<\/p>\n<h4><b>Step 2: Generate the PDF<\/b><\/h4>\n<p>func generatePDF(from text: String) -&gt; URL {<\/p>\n<p>let pdfURL = getDocumentsDirectory().appendingPathComponent(&#8220;GeneratedText.pdf&#8221;)<\/p>\n<p>&nbsp;<\/p>\n<p>let pageRect = CGRect(x: 0, y: 0, width: 595, height: 842) \/\/ A4 size<\/p>\n<p>let renderer = UIGraphicsPDFRenderer(bounds: pageRect)<\/p>\n<p>&nbsp;<\/p>\n<p>renderer.writePDF(to: pdfURL) { context in<\/p>\n<p>context.beginPage()<\/p>\n<p>&nbsp;<\/p>\n<p>let textRect = CGRect(x: 20, y: 40, width: pageRect.width &#8211; 40, height: pageRect.height &#8211; 80)<\/p>\n<p>let paragraphStyle = NSMutableParagraphStyle()<\/p>\n<p>paragraphStyle.lineSpacing = 6<\/p>\n<p>&nbsp;<\/p>\n<p>let attributes: [NSAttributedString.Key: Any] = [<\/p>\n<p>.font: UIFont.systemFont(ofSize: 16),<\/p>\n<p>.paragraphStyle: paragraphStyle<\/p>\n<p>]<\/p>\n<p>&nbsp;<\/p>\n<p>text.draw(in: textRect, withAttributes: attributes)<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>return pdfURL<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<h4><b>Step 3: Connect Button Action<\/b><\/h4>\n<p>@IBAction func generatePDF(_ sender: UIButton) {<\/p>\n<p>let text = textView.text ?? &#8220;&#8221;<\/p>\n<p>let pdfURL = generatePDF(from: text)<\/p>\n<p>print(&#8220;PDF saved at:&#8221;, pdfURL)<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Once tapped, this button generates a PDF containing the text entered by the user.<\/p>\n<h4><b>Step 4: Preview or Share the PDF (Optional)<\/b><\/h4>\n<p>You can preview or share the PDF using UIActivityViewController:<\/p>\n<p>let activityVC = UIActivityViewController(activityItems: [pdfURL], applicationActivities: nil)<\/p>\n<p>present(activityVC, animated: true)<\/p>\n<p>&nbsp;<\/p>\n<h3><b>Common Customizations<\/b><\/h3>\n<h4><b>Add Images to the PDF<\/b><\/h4>\n<p>let image = UIImage(named: &#8220;logo&#8221;)<\/p>\n<p>image?.draw(in: CGRect(x: 200, y: 100, width: 150, height: 150))<\/p>\n<p>&nbsp;<\/p>\n<h4><b>Change Font or Colors<\/b><\/h4>\n<p>Modify the attributes dictionary:<\/p>\n<p>.font: UIFont.boldSystemFont(ofSize: 18)<\/p>\n<p>.foregroundColor: UIColor.darkGray<\/p>\n<p>&nbsp;<\/p>\n<h4><b>Multiple Pages<\/b><\/h4>\n<p>Call context.beginPage() again to create a new page.<\/p>\n<h3><b>Where Is the PDF Stored?<\/b><\/h3>\n<p>The generated PDF is saved in:<\/p>\n<p>App Sandbox \u2192 Documents Directory<\/p>\n<p>&nbsp;<\/p>\n<p>You can access it via:<\/p>\n<ul>\n<li aria-level=\"1\">Finder (for simulator)<\/li>\n<li aria-level=\"1\">Files app (if shared)<\/li>\n<li aria-level=\"1\">Programmatic upload to a server<\/li>\n<\/ul>\n<h3><b>Common Issues &amp; Tips<\/b><\/h3>\n<p><b>Text getting cut off?<\/b><b><br \/>\n<\/b> \u2192 Increase page height or implement pagination.<\/p>\n<p><b>Large text content?<\/b><b><br \/>\n<\/b> \u2192 Split content across multiple pages.<\/p>\n<p><b>Performance concerns?<\/b><b><br \/>\n<\/b> \u2192 Avoid generating PDFs on the main thread for very large documents.<\/p>\n<h3><b>FAQs<\/b><\/h3>\n<p><b>Q: Is this compatible with SwiftUI?<\/b><b><br \/>\n<\/b> Yes. You can move the PDF logic into a separate class and call it from SwiftUI.<\/p>\n<p><b>Q: Can I upload the PDF to a server?<\/b><b><br \/>\n<\/b> Yes. Use URLSession after generating the file.<\/p>\n<p><b>Q: Is UIGraphicsPDFRenderer production-ready?<\/b><b><br \/>\n<\/b> Absolutely. It is Apple\u2019s recommended API.<\/p>\n<p><b>Q: Can I add tables or layouts?<\/b><b><br \/>\n<\/b> Yes, but you must manually calculate positions or use Core Text.<\/p>\n<h3><b>Conclusion<\/b><\/h3>\n<p>Generating PDFs in iOS using Swift is both powerful and efficient when using modern APIs like UIGraphicsPDFRenderer. With just a few lines of code, you can transform user input into professional, shareable documents\u2014all without relying on third-party libraries.<\/p>\n<p>If you\u2019re building <b>invoice systems, reporting tools, or document-based iOS apps<\/b>, this approach provides a scalable and future-proof solution.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Creating PDF files dynamically in an iOS application is a common requirement for features like invoices, reports, user-generated documents, or downloadable content. In this guide, you\u2019ll learn how to convert text content into a PDF file in Swift using modern<\/p>\n","protected":false},"author":1,"featured_media":234,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"spay_email":""},"categories":[1],"tags":[],"jetpack_featured_media_url":"https:\/\/i1.wp.com\/www.inwizards.com\/blog\/wp-content\/uploads\/2017\/02\/maxresdefault-1.jpg?fit=1280%2C720&ssl=1","_links":{"self":[{"href":"https:\/\/www.inwizards.com\/blog\/wp-json\/wp\/v2\/posts\/233"}],"collection":[{"href":"https:\/\/www.inwizards.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inwizards.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inwizards.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inwizards.com\/blog\/wp-json\/wp\/v2\/comments?post=233"}],"version-history":[{"count":7,"href":"https:\/\/www.inwizards.com\/blog\/wp-json\/wp\/v2\/posts\/233\/revisions"}],"predecessor-version":[{"id":3490,"href":"https:\/\/www.inwizards.com\/blog\/wp-json\/wp\/v2\/posts\/233\/revisions\/3490"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.inwizards.com\/blog\/wp-json\/wp\/v2\/media\/234"}],"wp:attachment":[{"href":"https:\/\/www.inwizards.com\/blog\/wp-json\/wp\/v2\/media?parent=233"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.inwizards.com\/blog\/wp-json\/wp\/v2\/categories?post=233"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inwizards.com\/blog\/wp-json\/wp\/v2\/tags?post=233"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}