Pdfkit

dpearson2699/swift-ios-skills/skills/pdfkit

作者 dpearson26998d90fd121a26無授權條款1.1K 個星標收錄於 2026年10月8日更新於 2026年10月8日儲存庫2 個月前更新

Display and manipulate PDF documents using PDFKit. Use when embedding PDFView to show PDF files, creating or modifying PDFDocument instances, adding annotations (highlights, notes, signature widgets), extracting text with PDFSelection, navigating pages, generating thumbnails, filling PDF forms, or wrapping PDFView in SwiftUI.

AI 產生的概覽

指導 Swift 開發者使用 Apple PDFKit 框架顯示、導覽、搜尋、註解與操作 PDF 文件。

功能
此技能為在 Swift 中使用 Apple PDFKit 框架提供參考指引與程式碼範例。內容涵蓋以 PDFView 呈現 PDF、載入與儲存 PDFDocument 實例、頁面導覽、以 PDFSelection 進行文字搜尋與擷取、加入螢光標示與便箋等註解、產生縮圖,以及將 PDFView 包裝進 SwiftUI。它也列出常見錯誤與審查清單。
適用情境
適用於建置需要顯示或修改 PDF 檔案的 iOS、iPadOS、macOS、tvOS 或 visionOS 應用程式。適合嵌入 PDF 檢視器、加入註解、擷取文字、填寫表單,或將 PDFView 整合至 SwiftUI 等任務。
執行需求
需要 Apple PDFKit 框架,以及搭載 Xcode 的 Swift 開發環境。不需要任何授權或 Info.plist 項目。此技能僅提供說明,不含指令碼,並引用一份額外的模式文件。

PDFKit

Display, navigate, search, annotate, and manipulate PDF documents with PDFView, PDFDocument, PDFPage, PDFAnnotation, and PDFSelection.

Contents

Setup

PDFKit requires no entitlements or Info.plist entries.

swift
import PDFKit
APIAvailability
PDFKit frameworkiOS/iPadOS/tvOS 11+, Mac Catalyst 13.1+, macOS 10.4+, visionOS 1.0+
Find interaction and page overlaysiOS/iPadOS 16+

Displaying PDFs

PDFView renders PDF content and handles zoom, scrolling, text selection, and page navigation.

swift
import PDFKitimport UIKit
class PDFViewController: UIViewController {    let pdfView = PDFView()
    override func viewDidLoad() {        super.viewDidLoad()        pdfView.frame = view.bounds        pdfView.autoresizingMask = [.flexibleWidth, .flexibleHeight]        view.addSubview(pdfView)
        pdfView.autoScales = true        pdfView.displayMode = .singlePageContinuous        pdfView.displayDirection = .vertical
        if let url = Bundle.main.url(forResource: "sample", withExtension: "pdf") {            pdfView.document = PDFDocument(url: url)        }    }}

Display Modes

ModeBehavior
.singlePageOne page at a time
.singlePageContinuousPages stacked vertically, scrollable
.twoUpTwo pages side by side
.twoUpContinuousTwo-up with continuous scrolling

Scaling and Appearance

swift
pdfView.autoScales = truepdfView.minScaleFactor = pdfView.scaleFactorForSizeToFitpdfView.maxScaleFactor = 4.0
pdfView.displaysPageBreaks = truepdfView.pageShadowsEnabled = truepdfView.interpolationQuality = .high

Loading Documents

PDFDocument loads from a URL, Data, or can be created empty.

swift
let fileDoc = PDFDocument(url: fileURL)let dataDoc = PDFDocument(data: pdfData)let emptyDoc = PDFDocument()

Password-Protected PDFs

swift
guard let document = PDFDocument(url: url) else { return }if document.isLocked {    if !document.unlock(withPassword: userPassword) {        // Show password prompt    }}

Saving and Page Manipulation

swift
document.write(to: outputURL)document.write(to: outputURL, withOptions: [    .ownerPasswordOption: "ownerPass", .userPasswordOption: "userPass"])let data = document.dataRepresentation()
// Pages are zero-based. Validate indices; out-of-range calls raise exceptions.let count = document.pageCountdocument.insert(PDFPage(), at: count)if document.pageCount > 2 {    document.removePage(at: 2)}if document.pageCount > 3 {    document.exchangePage(at: 0, withPageAt: 3)}

Page Navigation

PDFView provides built-in navigation with history tracking.

swift
// Go to a specific pagelet pageIndex = 5if let document = pdfView.document,   pageIndex >= 0,   pageIndex < document.pageCount,   let page = document.page(at: pageIndex) {    pdfView.go(to: page)}
// Sequential navigationpdfView.goToNextPage(nil)pdfView.goToPreviousPage(nil)pdfView.goToFirstPage(nil)pdfView.goToLastPage(nil)
// Check navigation stateif pdfView.canGoToNextPage { /* ... */ }
// History navigationif pdfView.canGoBack { pdfView.goBack(nil) }
// Go to a specific point on the current pageif let page = pdfView.currentPage {    let destination = PDFDestination(page: page, at: CGPoint(x: 0, y: 500))    pdfView.go(to: destination)}

Observing Page Changes

swift
NotificationCenter.default.addObserver(    self, selector: #selector(pageChanged),    name: .PDFViewPageChanged, object: pdfView)
@objc func pageChanged(_ notification: Notification) {    guard let page = pdfView.currentPage,          let doc = pdfView.document else { return }    let index = doc.index(for: page)    pageLabel.text = "Page \(index + 1) of \(doc.pageCount)"}

Text Search and Selection

Synchronous Search

swift
let results: [PDFSelection] = document.findString(    "search term", withOptions: [.caseInsensitive])

Asynchronous Search

Use PDFDocumentDelegate for background searches on large documents. Implement didMatchString(_:) to receive each match and documentDidEndDocumentFind(_:) for completion.

Incremental Search and Find Interaction

swift
// Find next match from current selectionlet next = document.findString("term", fromSelection: current, withOptions: [.caseInsensitive])
// System find bar; apply the Setup availability gatepdfView.isFindInteractionEnabled = true

Text Extraction

swift
let fullText = document.string                          // Entire documentlet firstPage = document.pageCount > 0 ? document.page(at: 0) : nillet pageText = firstPage?.string                        // Single pagelet attributed = firstPage?.attributedString            // With formatting
// Region-based extractionif let page = firstPage {    let selection = page.selection(for: CGRect(x: 50, y: 50, width: 400, height: 200))    let text = selection?.string}

Highlighting Search Results

swift
let results = document.findString("important", withOptions: [.caseInsensitive])for selection in results { selection.color = .yellow }pdfView.highlightedSelections = results
if let first = results.first {    pdfView.setCurrentSelection(first, animate: true)    pdfView.go(to: first)}

Annotations

Annotations are created with PDFAnnotation(bounds:forType:withProperties:) and added to a PDFPage.

Highlight Annotation

swift
func addHighlight(to page: PDFPage, selection: PDFSelection) {    let highlight = PDFAnnotation(        bounds: selection.bounds(for: page),        forType: .highlight, withProperties: nil    )    highlight.color = UIColor.yellow.withAlphaComponent(0.5)    page.addAnnotation(highlight)}

Text Note Annotation

swift
let note = PDFAnnotation(    bounds: CGRect(x: 100, y: 700, width: 30, height: 30),    forType: .text, withProperties: nil)note.contents = "This is a sticky note."note.color = .systemYellownote.iconType = .commentpage.addAnnotation(note)

Free Text Annotation

swift
let freeText = PDFAnnotation(    bounds: CGRect(x: 50, y: 600, width: 300, height: 40),    forType: .freeText, withProperties: nil)freeText.contents = "Added commentary"freeText.font = UIFont.systemFont(ofSize: 14)freeText.fontColor = .darkGraypage.addAnnotation(freeText)

Link Annotation

swift
let link = PDFAnnotation(    bounds: CGRect(x: 50, y: 500, width: 200, height: 20),    forType: .link, withProperties: nil)link.url = URL(string: "https://example.com")page.addAnnotation(link)
// Internal page linklink.destination = PDFDestination(page: targetPage, at: .zero)

Removing Annotations

swift
for annotation in page.annotations {    page.removeAnnotation(annotation)}

Common subtypes include .highlight, .underline, .strikeOut, .text, .freeText, .ink, .link, .line, .square, .circle, .stamp, and .widget.

Thumbnails

PDFThumbnailView

PDFThumbnailView shows a strip of page thumbnails linked to a PDFView.

swift
let thumbnailView = PDFThumbnailView()thumbnailView.pdfView = pdfViewthumbnailView.thumbnailSize = CGSize(width: 60, height: 80)thumbnailView.layoutMode = .verticalthumbnailView.translatesAutoresizingMaskIntoConstraints = falseview.addSubview(thumbnailView)

Generating Thumbnails Programmatically

swift
let thumbnail = page.thumbnail(of: CGSize(width: 120, height: 160), for: .mediaBox)
// All pageslet thumbnails = (0..<document.pageCount).compactMap {    document.page(at: $0)?.thumbnail(of: CGSize(width: 120, height: 160), for: .mediaBox)}

SwiftUI Integration

Wrap PDFView in a UIViewRepresentable for SwiftUI. PDF-specific wrappers that configure PDFView, pages, annotations, search, thumbnails, or overlays belong in this skill; route only generic representable lifecycle, layout, or SwiftUI state architecture questions to SwiftUI/UIKit interop guidance.

swift
import SwiftUIimport PDFKit
struct PDFKitView: UIViewRepresentable {    let document: PDFDocument
    func makeUIView(context: Context) -> PDFView {        let pdfView = PDFView()        pdfView.autoScales = true        pdfView.displayMode = .singlePageContinuous        pdfView.document = document        return pdfView    }
    func updateUIView(_ pdfView: PDFView, context: Context) {        if pdfView.document !== document {            pdfView.document = document        }    }}

Usage

swift
struct DocumentScreen: View {    let url: URL
    var body: some View {        if let document = PDFDocument(url: url) {            PDFKitView(document: document)                .ignoresSafeArea()        } else {            ContentUnavailableView("Unable to load PDF", systemImage: "doc.questionmark")        }    }}

For interactive wrappers with page tracking, annotation hit detection, and coordinator patterns, see references/pdfkit-patterns.md [blocked].

Page Overlays

PDFPageOverlayViewProvider places UIKit views on top of individual pages for interactive controls or custom rendering beyond standard annotations.

swift
class OverlayProvider: NSObject, PDFPageOverlayViewProvider {    func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? {        let overlay = UIView()        // Add custom subviews        return overlay    }}
class PDFOverlayController: UIViewController {    let pdfView = PDFView()    private let overlayProvider = OverlayProvider()
    override func viewDidLoad() {        super.viewDidLoad()        pdfView.pageOverlayViewProvider = overlayProvider    }}

pageOverlayViewProvider is weak, so keep the provider strongly owned. For overlay lifecycle and save handling, read references/pdfkit-patterns.md [blocked].

Common Mistakes

DON'T: Force-unwrap PDFDocument init

PDFDocument(url:) and PDFDocument(data:) are failable initializers.

swift
// WRONGlet document = PDFDocument(url: url)!
// CORRECTguard let document = PDFDocument(url: url) else { return }

DON'T: Forget autoScales on PDFView

Without autoScales, the PDF renders at its native resolution.

swift
// WRONGpdfView.document = document
// CORRECTpdfView.autoScales = truepdfView.document = document

DON'T: Ignore PDF coordinate system in annotations

PDF page coordinates have origin at the bottom-left with Y increasing upward -- opposite of UIKit.

swift
// WRONG: UIKit coordinateslet bounds = CGRect(x: 50, y: 50, width: 200, height: 30)
// CORRECT: PDF coordinates (origin bottom-left)let pageBounds = page.bounds(for: .mediaBox)let pdfY = pageBounds.height - 50 - 30let bounds = CGRect(x: 50, y: pdfY, width: 200, height: 30)

DON'T: Modify annotations on a background thread

PDFKit classes are not thread-safe.

swift
// WRONGDispatchQueue.global().async { page.addAnnotation(annotation) }
// CORRECTDispatchQueue.main.async { page.addAnnotation(annotation) }

DON'T: Compare PDFDocument with == in UIViewRepresentable

PDFDocument is a reference type. Use identity (!==).

swift
// WRONG: Always replaces documentfunc updateUIView(_ pdfView: PDFView, context: Context) {    pdfView.document = document}
// CORRECTfunc updateUIView(_ pdfView: PDFView, context: Context) {    if pdfView.document !== document {        pdfView.document = document    }}

Review Checklist

  • PDFDocument init uses optional binding, not force-unwrap
  • pdfView.autoScales = true set for proper initial display
  • Page indices checked against pageCount before access
  • displayMode and displayDirection configured to match design
  • Annotations use PDF coordinate space (origin bottom-left, Y up)
  • All PDFKit mutations happen on the main thread
  • Password-protected PDFs handled with isLocked / unlock(withPassword:)
  • SwiftUI wrapper uses !== identity check in updateUIView
  • PDFViewPageChanged notification observed for page tracking
  • PDFThumbnailView.pdfView linked to the main PDFView
  • Large-document search uses async beginFindString with delegate
  • Saved documents use write(to:withOptions:) when encryption needed

References

來源與署名

來源:dpearson2699/swift-ios-skills位於skills/pdfkit提交8d90fd1

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架

更多來自 dpearson2699/swift-ios-skills 的技能

Widgetkit

dpearson2699

指導實作、審查與改進 iOS、iPadOS、watchOS 與 CarPlay 上的 WidgetKit 小工具與控制項。

Software Development1.1K2 個月前更新

Weatherkit

dpearson2699

指導 iOS 開發者使用 WeatherService 取得 WeatherKit 預報、警報與署名資訊。

Software Development1.1K2 個月前更新

Vision Framework

dpearson2699

Implement computer vision features including text recognition (OCR), face detection, barcode scanning, image segmentation, object tracking, and document scanning in iOS apps. Covers both the modern Swift-native Vision API (iOS 18+) and legacy VNRequest patterns, VisionKit DataScannerViewController for live camera scanning, and CoreMLRequest/VNCoreMLRequest for custom model inference. Use when adding OCR, barcode scanning, face detection, or custom Core ML model inference with Vision.

待分類1.1K2 個月前更新

Tipkit

dpearson2699

Implement and review Apple TipKit feature-discovery UI for iOS 17+ apps. Use when adding or auditing in-app tips, contextual help, coach marks, Tip, TipView, popoverTip, rules, events, actions, display frequency, testing overrides, reusable tip identifiers, or iOS 18+ TipGroup and CloudKit tip sync; avoid for generic SwiftUI navigation or layout outside tip presentation.

待分類1.1K2 個月前更新

Tabletopkit

dpearson2699

指導使用 TabletopKit 在 visionOS 上打造多人空間桌遊,涵蓋棋具、座位、動作與 RealityKit 算繪。

Software Development1.1K2 個月前更新

Swiftui Webkit

dpearson2699

指導在 iOS 26 及更新版本的 SwiftUI App 中使用 WebKit for SwiftUI 嵌入與控制網頁內容。

Software Development1.1K2 個月前更新