accessorysetupkit
Discover and configure Bluetooth and Wi-Fi accessories using AccessorySetupKit. Use when presenting a privacy-preserving accessory picker, defining discovery…
Bridges UIKit and SwiftUI with UIViewRepresentable, UIViewControllerRepresentable, UIHostingController, UIHostingConfiguration, coordinator delegates, and UIKit automatic observation tracking for shared @Observable state. Use when wrapping UIKit-only or third-party UIKit
$ npx -y skills add dpearson2699/swift-ios-skills --skill swiftui-uikit-interop --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/swiftui-uikit-interopContext preview
The summary Claude sees to decide when to auto-load this skill.
Bridges UIKit and SwiftUI with UIViewRepresentable, UIViewControllerRepresentable, UIHostingController, UIHostingConfiguration, coordinator delegates, and UIKit automatic observation tracking for shared @Observable state. Use when wrapping UIKit-only or third-party UIKit
name: swiftui-uikit-interop description: "Bridges UIKit and SwiftUI with UIViewRepresentable, UIViewControllerRepresentable, UIHostingController, UIHostingConfiguration, coordinator delegates, and UIKit automatic observation tracking for shared @Observable state. Use when wrapping UIKit-only or third-party UIKit views/controllers in SwiftUI, embedding SwiftUI in UIKit, integrating mail/share/document/PDF/text-view surfaces, or migrating UIKit apps to SwiftUI incrementally."
Bridge UIKit and SwiftUI in both directions: wrap UIKit views and controllers, embed SwiftUI in UIKit screens, and synchronize state without duplicating lifecycle ownership.
See [references/representable-recipes.md](references/representable-recipes.md) for complete wrapping recipes and [references/hosting-migration.md](references/hosting-migration.md) for UIKit-to-SwiftUI migration patterns.
Use `UIViewRepresentable` to wrap any `UIView` subclass for use in SwiftUI.
struct WrappedTextView: UIViewRepresentable {
@Binding var text: String
func makeUIView(context: Context) -> UITextView {
// Called ONCE when SwiftUI inserts this view into the hierarchy.
// Create and return the UIKit view. One-time setup goes here.
let textView = UITextView()
textView.delegate = context.coordinator
textView.font = .preferredFont(forTextStyle: .body)
return textView
}
func updateUIView(_ uiView: UITextView, context: Context) {
// Called on EVERY SwiftUI state change that affects this view.
// Synchronize SwiftUI state into the UIKit view.
// Guard against redundant updates to avoid loops.
if uiView.text != text {
uiView.text = text
}
}
}| Method | When Called | Purpose | |--------|-----------|---------| | `makeCoordinator()` | Before `makeUIView`. Once per representable lifetime. | Create the delegate/datasource reference type. | | `makeUIView(context:)` | Once, when the representable enters the view tree. | Allocate and configure the UIKit view. | | `updateUIView(_:context:)` | Immediately after `makeUIView`, then on every relevant state change. | Push SwiftUI state into the UIKit view. | | `dismantleUIView(_:coordinator:)` | When the representable is removed from the view tree. | Clean up observers, timers, subscriptions. | | `sizeThatFits(_:uiView:context:)` | During layout, when SwiftUI needs the view's ideal size. iOS 16+. | Return a custom size proposal. |
**Why `updateUIView` is the most important method:** SwiftUI calls it every time any `@Binding`, `@State`, `@Environment`, or `@Observable` property read by the representable changes. All state synchronization from SwiftUI to UIKit happens here. If you skip a property, the UIKit view will fall out of sync.
static func dismantleUIView(_ uiView: UITextView, coordinator: Coordinator) {
// Remove observers, invalidate timers, cancel subscriptions.
// The coordinator is passed in so you can access state stored on it.
coordinator.cancellables.removeAll()
}@available(iOS 16.0, *)
func sizeThatFits(
_ proposal: ProposedViewSize,
uiView: UITextView,
context: Context
) -> CGSize? {
// Return nil to fall back to UIKit's intrinsicContentSize.
// Return a CGSize to override SwiftUI's sizing for this view.
let width = proposal.width ?? UIView.layoutFittingExpandedSize.width
let size = uiView.sizeThatFits(CGSize(width: width, height: .greatestFiniteMagnitude))
return size
}Use `UIViewControllerRepresentable` to wrap a `UIViewController` subclass -- typically for system pickers, document scanners, mail compose, or any controller that presents modally.
struct DocumentScannerView: UIViewControllerRepresentable {
@Binding var scannedImages: [UIImage]
@Environment(\.dismiss) private var dismiss
func makeUIViewController(context: Context) -> VNDocumentCameraViewController {
let scanner = VNDocumentCameraViewController()
scanner.delegate = context.coordinator
return scanner
}
func updateUIViewController(_ uiViewController: VNDocumentCameraViewController, context: Context) {
// Usually empty for modal controllers -- nothing to push from SwiftUI.
}
func makeCoordinator() -> Coordinator { Coordinator(self) }
}The coordinator captures delegate callbacks and routes results back to SwiftUI through the parent's `@Binding` or closures:
extension DocumentScannerView {
final class Coordinator: NSObject, VNDocumentCameraViewControllerDelegate {
let parent: DocumentScannerView
init(_ parent: DocumentScannerView) { self.parent = parent }
func documentCameraViewController(
_ controller: VNDocumentCameraViewController,
didFinishWith scan: VNDocumentCameraScan
) {
parent.scannedImages = (0..<scan.pageCount).map { scan.imageOfPage(at: $0) }
parent.dismiss()
}
func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController) {86 agent skills optimized for iOS 26+ development with Swift 6.3 and modern Apple frameworks.
Repo: dpearson2699/swift-ios-skills
Discover and configure Bluetooth and Wi-Fi accessories using AccessorySetupKit. Use when presenting a privacy-preserving accessory picker, defining discovery…
Implement, review, or improve Live Activities and Dynamic Island experiences in iOS apps using ActivityKit. Use when building real-time updating widgets for…
Measure ad effectiveness with privacy-preserving attribution using AdAttributionKit. Use when registering ad impressions, handling attribution postbacks,…
Implement AlarmKit alarms and countdown timers for iOS and iPadOS with Lock Screen, Dynamic Island, StandBy, and paired Apple Watch system UI. Covers…
Build iOS App Clips with invocation URLs, App Clip Codes, NFC, QR codes, Safari banners, Maps, Messages, target setup, App Store Connect experiences,…
Implement App Intents for Siri, Shortcuts, Spotlight, widgets, Control Center, and Apple Intelligence on iOS. Covers AppIntent actions, AppEntity and…