Community-maintained Agent Skills for complete Swift and Apple-platform app delivery.
73
92%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Medium
Suggest reviewing before use
Read this reference only when the task matches the sections below.
Display PDF documents in SwiftUI using PDFView from PDFKit. Supports loading from URL, Data, or file path, with configurable display mode and auto-scaling.
import SwiftUI
import PDFKit
struct PDFViewer: UIViewRepresentable {
let document: PDFDocument?
var displayMode: PDFDisplayMode = .singlePageContinuous
var autoScales: Bool = true
var displayDirection: PDFDisplayDirection = .vertical
var pageShadowsEnabled: Bool = true
func makeUIView(context: Context) -> PDFView {
let pdfView = PDFView()
pdfView.displayMode = displayMode
pdfView.displayDirection = displayDirection
pdfView.autoScales = autoScales
pdfView.pageShadowsEnabled = pageShadowsEnabled
pdfView.document = document
return pdfView
}
func updateUIView(_ uiView: PDFView, context: Context) {
// Update document if it changed (reference comparison)
if uiView.document !== document {
uiView.document = document
}
if uiView.displayMode != displayMode {
uiView.displayMode = displayMode
}
if uiView.autoScales != autoScales {
uiView.autoScales = autoScales
}
}
}extension PDFViewer {
/// Load a PDF from a URL (local file or remote).
init(url: URL, displayMode: PDFDisplayMode = .singlePageContinuous) {
self.document = PDFDocument(url: url)
self.displayMode = displayMode
}
/// Load a PDF from raw data.
init(data: Data, displayMode: PDFDisplayMode = .singlePageContinuous) {
self.document = PDFDocument(data: data)
self.displayMode = displayMode
}
}struct DocumentView: View {
let pdfURL: URL
var body: some View {
PDFViewer(url: pdfURL)
.ignoresSafeArea(edges: .bottom)
.navigationTitle("Document")
.navigationBarTitleDisplayMode(.inline)
}
}struct RemotePDFView: View {
let url: URL
@State private var document: PDFDocument?
@State private var isLoading = true
@State private var errorMessage: String?
var body: some View {
Group {
if let document {
PDFViewer(document: document)
} else if isLoading {
ProgressView("Loading PDF...")
} else if let errorMessage {
ContentUnavailableView(
"Could Not Load PDF",
systemImage: "doc.text.fill",
description: Text(errorMessage)
)
}
}
.task {
do {
let (data, _) = try await URLSession.shared.data(from: url)
document = PDFDocument(data: data)
} catch {
errorMessage = error.localizedDescription
}
isLoading = false
}
}
}struct NavigablePDFView: UIViewRepresentable {
let document: PDFDocument?
@Binding var currentPageIndex: Int
func makeCoordinator() -> Coordinator { Coordinator(self) }
func makeUIView(context: Context) -> PDFView {
let pdfView = PDFView()
pdfView.displayMode = .singlePageContinuous
pdfView.autoScales = true
pdfView.document = document
NotificationCenter.default.addObserver(
context.coordinator,
selector: #selector(Coordinator.pageChanged(_:)),
name: .PDFViewPageChanged,
object: pdfView
)
return pdfView
}
func updateUIView(_ uiView: PDFView, context: Context) {
if uiView.document !== document {
uiView.document = document
}
// Navigate to page if binding changed externally
if let doc = uiView.document,
let page = doc.page(at: currentPageIndex),
uiView.currentPage != page {
uiView.go(to: page)
}
}
static func dismantleUIView(_ uiView: PDFView, coordinator: Coordinator) {
NotificationCenter.default.removeObserver(coordinator)
}
final class Coordinator: NSObject {
var parent: NavigablePDFView
init(_ parent: NavigablePDFView) { self.parent = parent }
@objc func pageChanged(_ notification: Notification) {
guard let pdfView = notification.object as? PDFView,
let currentPage = pdfView.currentPage,
let document = pdfView.document else { return }
let index = document.index(for: currentPage)
if parent.currentPageIndex != index {
parent.currentPageIndex = index
}
}
}
}PDFView inherits from UIView. Use UIViewRepresentable, not UIViewControllerRepresentable.!== for identity comparison in updateUIView to avoid unnecessary reloads.NotificationCenter with .PDFViewPageChanged -- PDFView does not use a delegate pattern for page changes.dismantleUIView. Failing to remove NotificationCenter observers causes crashes after the view is removed.autoScales fits the PDF to the view width. Disable it if you want the user to start at a specific zoom level.PDFDocument loading can be expensive. Load asynchronously and assign on the main thread.Present the system SMS/MMS composer with pre-filled recipients, body, and optional attachments. Companion to Recipe 6 (MFMailComposeViewController).
import SwiftUI
import MessageUI
struct MessageComposer: UIViewControllerRepresentable {
let recipients: [String]
let body: String
var attachments: [MessageAttachment] = []
var onResult: ((MessageComposeResult) -> Void)?
@Environment(\.dismiss) private var dismiss
func makeCoordinator() -> Coordinator { Coordinator(self) }
func makeUIViewController(context: Context) -> MFMessageComposeViewController {
let controller = MFMessageComposeViewController()
controller.messageComposeDelegate = context.coordinator
controller.recipients = recipients
controller.body = body
for attachment in attachments {
controller.addAttachmentData(
attachment.data,
typeIdentifier: attachment.typeIdentifier,
filename: attachment.filename
)
}
return controller
}
func updateUIViewController(
_ uiViewController: MFMessageComposeViewController,
context: Context
) {
// Cannot update message compose after presentation
}
final class Coordinator: NSObject, MFMessageComposeViewControllerDelegate {
let parent: MessageComposer
init(_ parent: MessageComposer) { self.parent = parent }
func messageComposeViewController(
_ controller: MFMessageComposeViewController,
didFinishWith result: MessageComposeResult
) {
parent.onResult?(result)
parent.dismiss()
}
}
}
struct MessageAttachment {
let data: Data
let typeIdentifier: String // UTI, e.g., "public.jpeg"
let filename: String
}struct InviteView: View {
@State private var showMessage = false
var body: some View {
Button("Send Invite via SMS") {
guard MFMessageComposeViewController.canSendText() else { return }
showMessage = true
}
.sheet(isPresented: $showMessage) {
MessageComposer(
recipients: ["+1234567890"],
body: "Join me on this app!"
) { result in
switch result {
case .sent:
print("Message sent")
case .cancelled:
print("User cancelled")
case .failed:
print("Message failed")
@unknown default:
break
}
}
}
}
}struct SharePhotoView: View {
@State private var showMessage = false
let image: UIImage
var body: some View {
Button("Send Photo") {
guard MFMessageComposeViewController.canSendText(),
MFMessageComposeViewController.canSendAttachments() else {
return
}
showMessage = true
}
.sheet(isPresented: $showMessage) {
MessageComposer(
recipients: [],
body: "Check out this photo!",
attachments: [
MessageAttachment(
data: image.jpegData(compressionQuality: 0.8) ?? Data(),
typeIdentifier: "public.jpeg",
filename: "photo.jpg"
)
]
)
}
}
}canSendText() before presenting. If it returns false, do not display MFMessageComposeViewController; show fallback UI or disable the message action.canSendAttachments() before adding attachments. Not all devices or carriers support MMS attachments.MFMessageComposeViewControllerDelegate, not MFMessageComposeDelegate. It has a single required method.MFMailComposeViewController, the message composer API does not support changing fields after the controller is shown.canSendText() returns false on the simulator. Test on a physical device.Docs: MFMessageComposeViewController | MFMessageComposeViewControllerDelegate
.tessl-plugin
skills
accessorysetupkit
references
activitykit
adattributionkit
references
alarmkit
references
app-clips
app-intents
app-store-optimization
app-store-review
apple-on-device-ai
appmigrationkit
audioaccessorykit
references
authentication
references
avkit
background-processing
references
browserenginekit
callkit
references
carplay
cloudkit
contacts-framework
references
core-bluetooth
references
core-data
core-motion
references
core-nfc
references
coreml
references
cryptokit
cryptotokenkit
references
debugging-instruments
device-integrity
references
dockkit
energykit
references
eventkit
financekit
references
focus-engine
gamekit
healthkit
references
homekit
references
ios-accessibility
ios-app-workflow
references
ios-ettrace-performance
ios-localization
ios-memgraph-analysis
ios-networking
ios-simulator
references
metrickit
references
musickit
references
natural-language
references
paperkit
references
passkit
references
pdfkit
pencilkit
references
permissionkit
references
photokit
push-notifications
realitykit
references
relevancekit
references
scenekit
sensorkit
speech-recognition
references
spritekit
storekit
swift-api-design-guidelines
swift-architecture
references
swift-charts
swift-codable
references
swift-code-review
swift-concurrency
swift-formatstyle
references
swift-language
swift-security
references
swift-testing
swiftdata
swiftlint
swiftui-animation
swiftui-gestures
references
swiftui-layout-components
swiftui-liquid-glass
references
swiftui-patterns
swiftui-performance
swiftui-responsive-layout
swiftui-uikit-interop
swiftui-webkit
tabletopkit
tipkit
vision-framework
weatherkit
references