Creating a PDF in Swift with PDFKit

Learn how to create a PDF, work with Core Text and Core Graphics and share the created document by building an app that displays the user’s input on a flyer that can be shared with other iOS apps. By Bill Morefield.

4.9 (28) · 1 Review

Download materials
Save for later
Share

A PDF document acts as a bridge between online and printed documents. Adobe invented the PDF format, but it’s now an open standard that defines a document containing text, images and interactive elements.

This standard allows you to create electronic documents that look like printed documents. For many apps, creating a PDF adds value for the user.

PDFKit came to iOS in version 11.0. It provides libraries to display, create and manipulate PDF documents.

While the most common use of PDFKit is adding the ability to view PDF documents to an app, you can also use it to create and change PDF files.

In this tutorial, you’ll build an app that creates a simple flyer as a PDF based on information the user enters.

You should have a basic understanding of iOS app development before proceeding. Familiarity with Core Text and Core Graphics will be useful but isn’t required.

Getting Started

A PDF document consists of a single file ending in the .pdf extension. The file may include metadata that provides information about the document. The specification also allows simple password protection to restrict access and printing.

A PDF document contains pages corresponding to the pages of a printed document. Each page contains text, images, hyperlinks and/or annotations.

The page uses a coordinate system with 72 points to each printed inch. The coordinates originate at the bottom left of the page and increase going upward and to the right.

In this tutorial, you’ll build an app to create a simple flyer. The flyer will contain a title, image, body text and several tear-off tabs at the bottom. The app allows the user to enter the information for the flyer and select a photo either from the photo library or from the camera. Once the user has selected an image, a preview of that image will appear. Here’s how the flyer will look:

flyer design sketch

Begin by using the Download Materials button at the top or bottom of the page. Open the starter project, then build and run the app.

first screen

You’ll see a form to enter the information to create the flyer. The tool bar contains a Preview button that will create the PDF and open a view controller with a PDFView to show the flyer. There’s also a Share button that you’ll update so you can share the PDF with other iOS apps.

Creating a PDF With PDFKit

The key class to create a PDF is UIGraphicsPDFRenderer. The process is:

  1. Instantiate a UIGraphicsPDFRenderer object, optionally providing parameters to describe the document. You’ll usually want to do this, because if you don’t, iOS will use defaults based on the user’s device.
  2. Call either the pdfData(actions:) renderer to produce a Data object or the writePDF(to:withActions:) renderer to write the document directly to disk.
  3. Use Core Graphics instructions within the renderer method’s enclosure to create the document.

Next, you’ll create a new class to encapsulate the process of building a PDF. In the project choose File ▸ New ▸ File… and select the iOS ▸ Cocoa Touch Class template. Then, click Next.

Once you’ve done that, name the class PDFCreator and make it a subclass of NSObject. Ensure the Language is set to Swift.

Finally, click Next and then Create.

Importing PDFKit

To use PDFKit, you need to import it into the class. Add the following under import UIKit at the top of the file:

import PDFKit

Now, add this new method to create the PDF to PDFCreator:

func createFlyer() -> Data {
  // 1
  let pdfMetaData = [
    kCGPDFContextCreator: "Flyer Builder",
    kCGPDFContextAuthor: "raywenderlich.com"
  ]
  let format = UIGraphicsPDFRendererFormat() 
  format.documentInfo = pdfMetaData as [String: Any]

  // 2
  let pageWidth = 8.5 * 72.0
  let pageHeight = 11 * 72.0
  let pageRect = CGRect(x: 0, y: 0, width: pageWidth, height: pageHeight)

  // 3
  let renderer = UIGraphicsPDFRenderer(bounds: pageRect, format: format)
  // 4
  let data = renderer.pdfData { (context) in
    // 5
    context.beginPage()
    // 6
    let attributes = [
      NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 72)
    ]
    let text = "I'm a PDF!"
    text.draw(at: CGPoint(x: 0, y: 0), withAttributes: attributes)
  }

  return data
}

Here’s what this code does:

  1. You create a dictionary with the PDF’s metadata using predefined keys. You can find the full list of keys in Apple’s Auxiliary Dictionary Keys documentation. To set the metadata, you create a UIGraphicsPDFRendererFormat object and assign the dictionary to documentInfo.
  2. Recall that PDF files use a coordinate system with 72 points per inch. To create a PDF document with a specific size, multiply the size in inches by 72 to get the number of points. Here, you’ll use 8.5 x 11 inches, because that’s the standard U.S. letter size. You then create a rectangle of the size you just calculated.
  3. UIGraphicsPDFRenderer(bounds:format:) creates a PDFRenderer object with the dimensions of the rectangle and the format containing the metadata.
  4. pdfData(actions:) includes a block where you create the PDF. The renderer creates a Core Graphics context that becomes the current context within the block. Drawing done on this context will appear on the PDF.
  5. context.beginPage() starts a new PDF page. You must call beginPage() one time before giving any other drawing instructions. You can call it again to create multi-page PDF documents.
  6. Using draw(at:withAttributes:) on a String draws the string to the current context. You set the size of the string to 72 points.

Now that you have a simple PDF, you’ll set up the preview for the PDF in the app so you can view it.

Adding a PDF Preview

The starter app already contains a PDFView for preview, but it’s not ready to use. To start setting up your preview, open PDFPreviewViewController.swift. You’ll pass the PDF as a Data object to the class. At the top of PDFPreviewViewController, add a variable:

public var documentData: Data?

Now add the following code at the end of viewDidLoad():

if let data = documentData {
  pdfView.document = PDFDocument(data: data)
  pdfView.autoScales = true
}

When the preview loads, if documentData is set, PDFDocument(data:) creates a PDFDocument from the passed data.

PDFDocument is a PDFKit object that represents PDF data. Assign the document to the PDFView view and set the document to scale to fit the view.

Go back to FlyerBuilderViewController.swift and add the following method to the end of FlyerBuilderViewController. Make sure you add it to the class and not to an extension.

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  if segue.identifier == "previewSegue" {
    guard let vc = segue.destination as? PDFPreviewViewController else { return }
    let pdfCreator = PDFCreator()
    vc.documentData = pdfCreator.createFlyer()
  }
}

This method creates the PDF when the user calls the segue on the Preview button. It passes the PDF data to the destination PDFPreviewViewController.

Now, build and run the app. Click Preview in the tool bar and you should see a preview of the PDF file created in the app.

your first PDF

As mentioned earlier, the coordinates of a PDF originate at the bottom left corner. You might be surprised to see the text at the top of the PDF file since it’s drawn at coordinate (x: 0, y: 0). Why does that happen?

[spoiler title=”Answer”]pdfData(actions:) creates a Core Graphics context. The PDF coordinates and Core Graphics share the same point size, but coordinates for a Core Graphics context begin at the top left corner and increase down and to the right.

If you need to convert between the coordinate spaces, there are methods in PDFKit that will do so.[/spoiler]

Adding User Text to the PDF

Now it’s time to begin implementing the flyer. Open PDFCreator.swift and add the following lines at the top of PDFCreator.

let title: String
let body: String
let image: UIImage
let contactInfo: String

init(title: String, body: String, image: UIImage, contact: String) {
  self.title = title
  self.body = body
  self.image = image
  self.contactInfo = contact
}

This adds properties to store the title, body text, image and contact information for the flyer. You also define a custom initializer method to set the variables.

Since you have a title for the PDF, you can now add it to the metadata by opening PDFCreator.swift and updating pdfMetaData to:

let pdfMetaData = [
  kCGPDFContextCreator: "Flyer Builder",
  kCGPDFContextAuthor: "raywenderlich.com",
  kCGPDFContextTitle: title
]

Adding the Title With Core Text

You want the title of the flyer to appear at the center and near the top of the PDF page. To make the creation code easier to follow and maintain, you’ll create a separate method for each part of the flyer.

When adding text, you’ll want to take advantage of the additional layout functionality provided by Core Text. So add the following new method at the bottom of PDFCreator:

func addTitle(pageRect: CGRect) -> CGFloat {
  // 1
  let titleFont = UIFont.systemFont(ofSize: 18.0, weight: .bold)
  // 2
  let titleAttributes: [NSAttributedString.Key: Any] = 
    [NSAttributedString.Key.font: titleFont]
  // 3
  let attributedTitle = NSAttributedString(
    string: title, 
    attributes: titleAttributes
  ) 
  // 4
  let titleStringSize = attributedTitle.size()
  // 5
  let titleStringRect = CGRect(
    x: (pageRect.width - titleStringSize.width) / 2.0,
    y: 36, 
    width: titleStringSize.width,
    height: titleStringSize.height
  )
  // 6
  attributedTitle.draw(in: titleStringRect)
  // 7
  return titleStringRect.origin.y + titleStringRect.size.height
}

Here’s what this method does:

  1. You create an instance of the system font that has a size of 18 points and is in bold.
  2. You create an attributes dictionary and set the NSAttributedString.Key.font key to this font.
  3. Then, you create NSAttributedString containing the text of the title in the chosen font.
  4. Using size() on the attributed string returns a rectangle with the size the text will occupy in the current context.
  5. You now create a rectangle 36 points from the top of the page which horizontally centers the title on the page. The figure below shows how to calculate the x coordinate needed to center the text.

    You subtract the width of the string from the width of the page to calculate the remaining space. Dividing this amount by two evenly splits the space on each side of the text.

  6. Using draw(in:) on NSAttributedString draws it inside the rectangle.
  7. This code adds the y coordinate of the rectangle to the height of the rectangle to find the coordinate of the bottom of the rectangle, as shown in the following figure. The code then returns this coordinate to the caller.

graphic to explain how to center text

You’ll do more with this technique for placing text later in this tutorial, so make sure you understand it before moving forward.

You now need to call the new method when creating the PDF. In createFlyer(), replace this code:

let attributes = [
  NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 72)
]
let text = "I'm a PDF!"
text.draw(at: CGPoint(x: 0, y: 0), withAttributes: attributes)

with a call to the new method:

let titleBottom = addTitle(pageRect: pageRect)

Next, you need to pass the title to PDFCreator. So, open FlyerBuilderViewController.swift and replace the implementation of prepare(for:sender:) with:

guard
  segue.identifier == "previewSegue",
  let vc = segue.destination as? PDFPreviewViewController,
  let title = flyerTextEntry.text
  else {
    return
}

let pdfCreator = PDFCreator(
  title: title,
  body: "",
  image: UIImage(),
  contact: ""
)
vc.documentData = pdfCreator.createFlyer()

The PDFCreator initializer sets the title and provides placeholder values for the remaining elements. You’ll replace these as you implement each part of the flyer.

Now, build and run the app. Enter a title, then tap Preview. You should see your title text centered at the top of the page.

Flyer title

Adding Paragraph Text

If you try different titles with the app, you might notice a problem: This method of positioning text only works when the text fits onto a single line. A very long title will go off the sides of the PDF.

title is too long and wraps

While a title will normally be a single line, most text will cover several lines on the page. Fortunately, Core Text provides the NSParagraphStyle class to fix this problem. So now, you’ll find out how to add wrapped text to the app.

Using NSParagraphStyle

To introduce wrapped text to your app, add this new method to the bottom of PDFCreator in PDFCreator.swift:

func addBodyText(pageRect: CGRect, textTop: CGFloat) {
  let textFont = UIFont.systemFont(ofSize: 12.0, weight: .regular)
  // 1
  let paragraphStyle = NSMutableParagraphStyle()
  paragraphStyle.alignment = .natural
  paragraphStyle.lineBreakMode = .byWordWrapping
  // 2
  let textAttributes = [
    NSAttributedString.Key.paragraphStyle: paragraphStyle,
    NSAttributedString.Key.font: textFont
  ]
  let attributedText = NSAttributedString(
    string: body, 
    attributes: textAttributes
  )
  // 3
  let textRect = CGRect(
    x: 10, 
    y: textTop, 
    width: pageRect.width - 20,
    height: pageRect.height - textTop - pageRect.height / 5.0
  )
  attributedText.draw(in: textRect)
}

Here’s what’s different from the method you used to draw a title:

  1. You create an NSMutableParagraphStyle object to define how text should flow and wrap. Natural alignment sets the alignment based on the localization of the app. Lines are set to wrap at word breaks.
  2. The dictionary holds the text attributes that set the paragraph style in addition to the font. You create an NSAttributedString that combines the text and formatting, just like you did with the title.
  3. The rectangle for the text is a little different. It offsets 10 points from the left and sets the top at the passed value. The width is set to the width of the page minus a margin of 10 points on each side. The height is the distance from the top to 1/5 of the page height from the bottom.

Your next step is to update createFlyer() to add the the body text. You’ll also add a half-inch of space between the title and body text. Below the call to addTitle(), add the following:

addBodyText(pageRect: pageRect, textTop: titleBottom + 36.0)

Next, you need to pass the text for the flyer to the preview controller. To do this, open FlyerBuilderViewController.swift and replace the implementation of prepare(for:sender:) with:

guard
  segue.identifier == "previewSegue",
  let vc = segue.destination as? PDFPreviewViewController,
  let title = flyerTextEntry.text,
  let body = bodyTextView.text
  else {
    return
}

let pdfCreator = PDFCreator(
  title: title,
  body: body,
  image: UIImage(),
  contact: ""
)
vc.documentData = pdfCreator.createFlyer()

Build and run your app. Enter a title and some text for the body of the flyer and tap Preview. Look, your PDF now shows both types of text!

body text added

Your next goal is to give the user the ability to add an image to the flyer.

Adding Images

The starter project lets the user select an image from the photo library or the camera. The chosen image can be horizontal or vertical and of any size. Adding an image to the page requires sizing the image while retaining the image’s aspect ratio and orientation.

To get started, add the following method at the end of PDFCreator:

func addImage(pageRect: CGRect, imageTop: CGFloat) -> CGFloat {
  // 1
  let maxHeight = pageRect.height * 0.4
  let maxWidth = pageRect.width * 0.8
  // 2
  let aspectWidth = maxWidth / image.size.width
  let aspectHeight = maxHeight / image.size.height
  let aspectRatio = min(aspectWidth, aspectHeight)
  // 3
  let scaledWidth = image.size.width * aspectRatio
  let scaledHeight = image.size.height * aspectRatio
  // 4
  let imageX = (pageRect.width - scaledWidth) / 2.0
  let imageRect = CGRect(x: imageX, y: imageTop,
                         width: scaledWidth, height: scaledHeight)
  // 5
  image.draw(in: imageRect)
  return imageRect.origin.y + imageRect.size.height
}

Here’s how this code fits the image onto the page.

  1. Define that the image can be at most 40% of the page’s height and 80% of the page’s width.
  2. Next, you calculate the ratio of the maximum width to the actual width of the image, then do the same for the height. You take the smaller of these two ratios as the dimension to resize the image against. This ratio maximizes the size of the image while ensuring that it fits within the constraints.
  3. Calculate the scaled height and width for the image using the ratio.
  4. Calculate the horizontal offset to center the image, just as you did earlier with the title text. Create a rectangle at this coordinate with the size you’ve calculated.
  5. Draw the image using draw(in:) on UIImage. This method scales the image to fit within the rectangle. Finally, return the coordinate of the bottom of the image to the caller, just as you did with the title text.

You’ll insert the image between the title and the body text to match the flyer design. In createFlyer(), replace the call to addBodyText(pageRect:textTop:) with the following:

let imageBottom = addImage(pageRect: pageRect, imageTop: titleBottom + 18.0)
addBodyText(pageRect: pageRect, textTop: imageBottom + 18.0)

Next, you need to pass the image to PDFCreator. Open FlyerBuilderViewController.swift and replace the implementation of prepare(for:sender:) with:

if 
  let title = flyerTextEntry.text, 
  let body = bodyTextView.text,
  let image = imagePreview.image {
    let pdfCreator = PDFCreator(title: title, body: body,
                                image: image, contact: "")
    vc.documentData = pdfCreator.createFlyer()
}

Build and run the app and you should see your image on the page. Try photos of different sizes and orientations and you can see how the code fits them onto the page.

image added to flyer

Drawing Graphics

Flyers often include tear-offs at the bottom with contact information that readers can take with them. Your next step will add that feature to the flyer.

You’ll implement the tear-offs in two steps. First, you’ll add lines on the page to separate the tear-off tabs. Then you’ll add the contact information to each tab.

Begin by adding a new method at the end of PDFCreator.

// 1
func drawTearOffs(_ drawContext: CGContext, pageRect: CGRect,
                  tearOffY: CGFloat, numberTabs: Int) {
  // 2
  drawContext.saveGState()
  // 3
  drawContext.setLineWidth(2.0)

  // 4
  drawContext.move(to: CGPoint(x: 0, y: tearOffY))
  drawContext.addLine(to: CGPoint(x: pageRect.width, y: tearOffY))
  drawContext.strokePath()
  drawContext.restoreGState()

  // 5
  drawContext.saveGState()
  let dashLength = CGFloat(72.0 * 0.2)
  drawContext.setLineDash(phase: 0, lengths: [dashLength, dashLength])
  // 6
  let tabWidth = pageRect.width / CGFloat(numberTabs)
  for tearOffIndex in 1..<numberTabs {
    // 7
    let tabX = CGFloat(tearOffIndex) * tabWidth
    drawContext.move(to: CGPoint(x: tabX, y: tearOffY))
    drawContext.addLine(to: CGPoint(x: tabX, y: pageRect.height))
    drawContext.strokePath()
  }
  // 7
  drawContext.restoreGState()
}
  1. This new method takes several parameters. First comes the graphics context to draw on (more on that in a moment) and then comes the rectangle for the page. You also pass the location for the top of the tabs along with the number of tabs to create.
  2. You save the current state of the graphics context. Later, you'll restore the context, undoing all changes made between the two calls. This pairing keeps the environment consistent at the start of each step.
  3. The code then sets the width of stroked lines to two points.
  4. Next, you draw a horizontal line from the left to right side of the page at the passed height and then restore the state saved earlier.
  5. After saving the current context, you draw dashed vertical lines between the tabs. To create a dashed line in Core Graphics, you define an array with the length of the alternating solid and empty segments. Here, the array defines both the dashes and the spaces as 0.2 inches long.
  6. To calculate the width of each tab in points, you divide the width of the page by the number of tabs. Next, you loop and draw the dashed line between each tab.
  7. Within the loop, you calculate the horizontal location of the dividing line by multiplying the tab number by the width of each line. Then you draw the line from the top of the tab, where you drew the horizontal line, to the bottom of the page.
  8. After you've drawn all the lines, you restore the graphics state.

You need a Core Graphics context to pass to this method. Use cgContext on the UIGraphicsPDFRendererContext to get one.

To do this, go to createFlyer() and add the following code after addBodyText(pageRect:textTop:):

let context = context.cgContext
drawTearOffs(context, pageRect: pageRect, tearOffY: pageRect.height * 4.0 / 5.0,
             numberTabs: 8)

Build and run the app. Enter a title, body and image for the flyer and tap Preview. You should see the tear-off lines at the bottom of the page.

You'll still need to cut along the dotted lines yourself. Apps can't do everything yet. :]

tear offs drawn

So you have your tear-off tabs, but they are still blank. In the next step, you'll add contact information to the tabs.

Adding Rotated Text

Of course, you want your text to run across the long side of your pull-off tags, so you'll need to rotate the text. To do this, open PDFCreator.swift and add the following method to the end of the class:

func drawContactLabels(
    _ drawContext: CGContext, 
    pageRect: CGRect, numberTabs: Int) {
  let contactTextFont = UIFont.systemFont(ofSize: 10.0, weight: .regular)
  let paragraphStyle = NSMutableParagraphStyle()
  paragraphStyle.alignment = .natural
  paragraphStyle.lineBreakMode = .byWordWrapping
  let contactBlurbAttributes = [
    NSAttributedString.Key.paragraphStyle: paragraphStyle,
    NSAttributedString.Key.font: contactTextFont
  ]
  let attributedContactText = NSMutableAttributedString(
                                string: contactInfo,
                                attributes: contactBlurbAttributes
                              ) 
  // 1
  let textHeight = attributedContactText.size().height
  let tabWidth = pageRect.width / CGFloat(numberTabs)
  let horizontalOffset = (tabWidth - textHeight) / 2.0
  drawContext.saveGState()
  // 2
  drawContext.rotate(by: -90.0 * CGFloat.pi / 180.0)
  for tearOffIndex in 0...numberTabs {
    let tabX = CGFloat(tearOffIndex) * tabWidth + horizontalOffset
    // 3
    attributedContactText.draw(at: CGPoint(x: -pageRect.height + 5.0, y: tabX))
  }
  drawContext.restoreGState()
}

This method is an extension of the process used to add the body text to the PDF. To make the text run vertically upward, you use a rotation transform. Rotation changes how you determine the layout. Here are the changes caused by rotating the text:

  1. You use size() to find the smallest size required to draw the string in the current context. The rotation swaps the horizontal and vertical elements in the drawn text. So you use the height of the text to determine the offset to center the text in the tab, rather than the width.
  2. You want to rotate the text 90 degrees counterclockwise. You indicate counterclockwise with a negative angle transform. Core Graphics expects angles specified in radians.
  3. The rotation also affects the coordinate system, as shown in the diagram below. This rotation changes the direction of the axis and the direction the coordinate increases. While the origin hasn't moved, you swap the X and Y values, as the X coordinate now decreases down the page and the Y coordinate increases to the right on the page.

rotation visualization

Add the following line to the end of createFlyer() to draw the contact info:

drawContactLabels(context, pageRect: pageRect, numberTabs: 8)

You need to send the contact information to PDFCreator. Open FlyerBuilderViewController.swift and — one last time — replace the implementation of prepare(for:sender:) with:

guard
  segue.identifier == "previewSegue",
  let vc = segue.destination as? PDFPreviewViewController,
  let title = flyerTextEntry.text,
  let body = bodyTextView.text,
  let image = imagePreview.image,
  let contact = contactTextView.text
  else {
    return
}

let pdfCreator = PDFCreator(
  title: title,
  body: body,
  image: image,
  contact: contact
)
vc.documentData = pdfCreator.createFlyer()

Build and run your app, enter information for all fields and then tap Preview. You should see the final PDF.

completed flyer

Your app creates a PDF, but it's not that useful trapped inside the app. So in the next step, you'll add the ability to share the PDF to the app.

Sharing the PDF

Open FlyerBuilderViewController.swift and replace the contents of shareAction() with:

// 1
guard 
  let title = flyerTextEntry.text, 
  let body = bodyTextView.text,
  let image = imagePreview.image, 
  let contact = contactTextView.text 
  else {
    // 2
    let alert = UIAlertController(
      title: "All Information Not Provided",
      message: "You must supply all information to create a flyer.",
      preferredStyle: .alert
    )
      alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
      present(alert, animated: true, completion: nil)
      return
  }
// 3
let pdfCreator = PDFCreator(
  title: title,
  body: body, 
  image: image, 
  contact: contact
) 
let pdfData = pdfCreator.createFlyer()
let vc = UIActivityViewController(
  activityItems: [pdfData],
  applicationActivities: []
) 
present(vc, animated: true, completion: nil)

Here you:

  1. First, ensure the user added all information for the flyer.
  2. If not, you create an informational message, display it to the user and return.
  3. If the user has added all the information for the flyer, you create the PDF. You then create a UIActivityViewController to provide and display the shared object's data.

Build and run the app, enter all information, then tap Share at the bottom-right side of the app. You'll see options to share the PDF file. Unfortunately, the simulator doesn't provide many useful options, so you may want to run the app on a real device.

your share sheet

One Final Touch

That check before sharing the PDF is a nice user interface feature. So now you'll add a check to make sure all information is there when the user requests a preview as well.

Open FlyerBuilderViewController.swift file and, above prepare(for:sender), add this new method to determine if the segue should occur:

override func shouldPerformSegue(withIdentifier identifier: String,
                                 sender: Any?) -> Bool {
  if 
    let _ = flyerTextEntry.text, 
    let _ = bodyTextView.text,
    let _ = imagePreview.image, 
    let _ = contactTextView.text { 
      return true 
    }

  let alert = UIAlertController(
    title: "All Information Not Provided",
    message: "You must supply all information to create a flyer.", 
    preferredStyle: .alert
  )
  alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
  present(alert, animated: true, completion: nil)

  return false
}

This code checks that the user has entered something in each text field and has selected an image. If so, it allows the segue. If not, it displays an error message and stops the segue.

Where to Go From Here?

You can download the final project using the Download Materials button at the top or bottom of this page.

In this tutorial, you've built an app that creates a PDF file using PDFKit. The user's input produces a flyer that you can share with other iOS apps. In the process, you learned to create a PDF, work with Core Text and Core Graphics and share the created document.

For more on PDFKit, look at Apple's PDFKit Documentation and the Introducing PDFKit on iOS — WWDC 2017 session.

For more on Core Text, see our Core Text Tutorial.

To learn more about Core Graphics, see Core Graphics Tutorial Part 1: Getting Started and Core Graphics Tutorial Part 2: Gradients and Contexts.

We hope you found this tutorial helpful. If you have any questions or comments, please join the forum discussion below.