| name | uikit |
| description | Write, review, and modernize UIKit code for iOS 26 / Swift 6.2 — UIViewController/UIView lifecycle, Auto Layout, UITableView/UICollectionView with diffable data sources, navigation and coordinators, MVVM/VIPER, retain-cycle debugging, accessibility, iOS 26 Liquid Glass, SwiftUI bridging (UIViewRepresentable, UIHostingController), keyboard-safe layout, PencilKit, and iPad Stage Manager. Use when reading, writing, reviewing, or refactoring any UIKit project or migrating legacy patterns. Triggers: "review my UIKit code", "UIViewController", "UITableView", "Auto Layout constraints", "fix the retain cycle", "diffable data source", "Liquid Glass". Not for SwiftUI-only projects. |
| license | MIT |
| metadata | {"version":"1.1","ios-baseline":"26","swift-baseline":"6.2"} |
UIKit (iOS 26 / Swift 6.2)
Authoritative skill for production UIKit work — reviewing existing code,
writing new code, and refactoring legacy patterns. The guidance targets the
modern era (iOS 26, Swift 6.2, Xcode 26) while staying honest about
deployment-target constraints: every modern API below is tagged with its
minimum iOS version, and you must check the project's deployment target before
recommending it.
Core operating rules
- iOS 26 is the latest release. Target iOS 17+ as the minimum
deployment target for new code unless the project says otherwise. Target
Swift 6.2+ with modern Swift concurrency.
- Respect the project's deployment target. Before suggesting any API,
verify its availability. If the project targets an older iOS version,
recommend the best available alternative and wrap newer APIs in
if #available(iOS …, *). The reference files tag key APIs with their iOS
version. Never suggest an API unavailable at the minimum target without a
fallback.
- This is a UIKit codebase. Do not suggest SwiftUI replacements unless the
user explicitly asks. (For incremental SwiftUI adoption inside UIKit, the
bridge APIs —
UIHostingConfiguration, UIHostingController,
UIHostingSceneDelegate — are in scope; wholesale rewrites are not.)
- Do not introduce third-party frameworks without asking first.
- One type per file. Break classes, structs, and enums into separate Swift
files. Folder layout follows app features.
- Prefer programmatic UI with Auto Layout anchors over Storyboards and XIBs
for new code, unless the project already uses Interface Builder extensively.
- Report only genuine problems. Do not nitpick or invent issues.
What this skill decides for you
UIKit has no single "right way" — it spans three architectures and three
binding mechanisms. Use these decision trees to commit to one before writing
code.
Which architecture?
Static content (About, Legal, simple settings)?
└── Plain MVC view controller. Architecture overhead is not worth it.
Standard feature screen (list, detail, form with networking)?
└── MVVM — the dominant production architecture. ViewModel owns state + logic,
view controller binds and renders. (references/mvvm.md)
Complex multi-state feature at scale, large team, strict testability mandate?
└── VIPER — maximum separation, every layer independently testable behind
protocols. Tradeoff is 5-15 files per module. (references/viper.md)
Reusable UI component (cell, widget, custom control)?
└── A custom UIView subclass — NOT a screen architecture.
For project-wide architecture strategy beyond UIKit specifics, see the
ios-app-architecture skill.
Which binding mechanism (UIKit has no built-in binding)?
Minimum iOS target?
├── iOS 15+ and greenfield/migrating → async/await for fetching + Combine for
│ UI binding (@Published + sink). Best of both.
├── iOS 13–14 → Combine (@Published + sink, PassthroughSubject
│ for one-shot events like navigation/alerts).
└── < iOS 13 OR staying on GCD → Closures / a Bindable<T> wrapper, GCD in services.
Full decision matrix, retain-cycle rules, and the GCD→Combine→async migration
path are in references/mvvm.md.
Where does this code belong? (the universal placement test)
HOW it looks on screen (layout, animation, UIKit delegates)? → View / ViewController
WHAT data to fetch, filter, sort, validate, combine? → ViewModel / Interactor
HOW to FORMAT data for display, WHICH state to show? → ViewModel / Presenter
HOW to navigate to another screen? → Coordinator / Router
A plain data container? → Model / Entity (struct)
HOW to talk to a network/database? → Service (injected protocol)
Review workflow
When reviewing UIKit code, work through the relevant reference files and report
findings by file. Load only the references the task needs:
- Deprecated API → references/api-modern.md
- View lifecycle / composition / custom drawing → references/views.md
- Auto Layout, anchors, stack views, safe area → references/layout.md
- View controller lifecycle, containment, Massive-VC → references/controllers.md
- Navigation, coordinators, modal presentation → references/navigation.md
- Table/collection views, diffable data sources → references/collections.md
- HIG, Dark Mode, traits, Liquid Glass → references/design.md
- Accessibility (VoiceOver, Dynamic Type) → references/accessibility.md
- Performance (off-screen rendering, images, main thread) → references/performance.md
- Concurrency, thread safety, GCD→async migration → references/concurrency.md
- Modern Swift idioms + Obj-C interop → references/swift.md
- Memory management, retain cycles, deinit → references/memory.md
- MVVM architecture (bindings, ViewState, coordinators) → references/mvvm.md
- VIPER architecture (5 layers, ownership chain) → references/viper.md
- Structured accessibility audit (P0/P1/P2 + manual tests) → references/accessibility-audit.md
- Keyboard-safe layout (input bars, scrollable editors) → references/keyboard.md
- Interface Builder / XIB runtime bugs, the XIB↔Swift split → references/interface-builder.md
- SwiftUI ↔ UIKit bridging (representables, gestures, hosting) → references/swiftui-bridging.md
- PencilKit / Apple Pencil / drawing canvases → references/pencilkit-canvas.md
- Pointer interactions + the focus engine (iPad/macOS/tvOS) → references/pointer-and-focus.md
- iPad multi-window, Stage Manager, adaptive layout → references/ipad-multiwindow.md
- Global blocking overlay via an extra
UIWindow → references/windows-and-overlays.md
Output format for code reviews
Organize findings by file. For each issue:
- State the file and relevant line(s).
- Name the rule being violated (e.g. "Use
UIAlertController instead of
UIAlertView").
- Show a brief before/after code fix.
Skip files with no issues. End with a prioritized summary of the most
impactful changes to make first. Example:
ProfileViewController.swift
Line 8: Use UIAlertController instead of deprecated UIAlertView.
let alert = UIAlertView(title: "Error", message: msg, delegate: self, cancelButtonTitle: "OK")
alert.show()
let alert = UIAlertController(title: "Error", message: msg, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true)
Line 24: Set translatesAutoresizingMaskIntoConstraints = false before adding constraints, and batch-activate.
view.addSubview(label)
label.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
label.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: view.topAnchor),
label.leadingAnchor.constraint(equalTo: view.leadingAnchor)
])
Summary
- Deprecated API (high):
UIAlertView on line 8 → UIAlertController.
- Layout (medium): missing
translatesAutoresizingMaskIntoConstraints + un-batched constraints on line 24.
The highest-value rules (memorize these)
These are the violations that cause real production bugs, ordered by how often
they bite.
translatesAutoresizingMaskIntoConstraints = false on every view before
programmatic Auto Layout, and batch-activate with NSLayoutConstraint.activate([...]).
[weak self] in every long-lived closure — Combine sink, GCD
completion handlers, NotificationCenter blocks, Timer targets, and
diffable data source cellProvider. The retain-cycle paths are spelled out
in references/memory.md.
.receive(on: DispatchQueue.main) before any UI update in a Combine
pipeline — @Published emits on whatever thread set the property.
- All UI updates on the main thread — prefer
@MainActor over manual
DispatchQueue.main.async.
- Never
assign(to:on:) to a property of self when self owns the
cancellables set — it retains strongly and leaks. Use sink { [weak self] }.
- ViewModel/Presenter imports
Foundation only, never UIKit — the
single most-violated architecture rule; it's what makes the layer testable.
- Delegates are
weak, and weak-referenced protocols are constrained to
AnyObject.
- Cancel
Tasks in deinit — UIKit does NOT auto-cancel them the way
SwiftUI's .task modifier does.
- No layout/geometry work in
viewDidLoad() — bounds aren't final. Use
viewIsAppearing(_:) (back-deployed to iOS 13+) or viewDidLayoutSubviews().
- Diffable data sources + compositional layout for any non-trivial list —
eliminates "invalid number of items" crashes and gives free animations.
iOS 26 headline changes
Apps compiled with Xcode 26 automatically adopt Liquid Glass. The
practical implications you'll review for:
- Liquid Glass materials —
UIGlassEffect, UIButton.Configuration.glass()
family, UIScrollEdgeEffect for content fading under glass bars. (references/design.md)
updateProperties() — a new update-pass stage (Traits → updateProperties()
→ layoutSubviews() → Display) for property/style hydration that must run
before layout without forcing a full layout pass. (references/views.md)
- Automatic
@Observable tracking — UIKit now auto-tracks @Observable
objects accessed inside layoutSubviews(), updateProperties(),
updateConstraints(), draw(_:), and cell configurationUpdateHandlers. No
manual setNeedsLayout(). Back-deployable to iOS 18 via
UIObservationTrackingEnabled = YES in Info.plist. (references/views.md)
UICornerConfiguration — declarative per-corner rounding (.capsule(),
.concentric) replacing manual layer.cornerRadius + maskedCorners.
- Scene lifecycle is now mandatory — after iOS 26, apps that have not
adopted
UIScene/UISceneDelegate will not launch.
- Strongly typed
NotificationCenter.Message — no more userInfo
dictionary casting for keyboard and system notifications.
Full per-area iOS 26 detail lives at the bottom of each relevant reference file.
References
| File | Covers |
|---|
| references/api-modern.md | Deprecated UIKit APIs → modern replacements; iOS 26 additions |
| references/views.md | UIView lifecycle, composition, custom drawing, updateProperties(), observation tracking |
| references/layout.md | Auto Layout anchors, UIStackView, intrinsic size, safe area, scroll-view layout |
| references/controllers.md | UIViewController lifecycle, containment, avoiding Massive View Controller |
| references/navigation.md | Navigation controllers, coordinator pattern, sheets/detents, modal presentation |
| references/collections.md | Diffable data sources, compositional layout, cell registration, prefetching |
| references/design.md | HIG, Dark Mode, traits, SF Symbols, Liquid Glass, adaptive layout |
| references/accessibility.md | VoiceOver, Dynamic Type, traits, announcements |
| references/performance.md | Off-screen rendering, image decoding/caching, main-thread budget |
| references/concurrency.md | Main-thread safety, async/await, GCD→Swift concurrency migration |
| references/swift.md | Modern Swift idioms, Foundation APIs, Objective-C interop |
| references/memory.md | Retain cycles, ownership chains, KVO/notification/Timer cleanup, leak tests |
| references/mvvm.md | MVVM: bindings (Combine/GCD/async + operator selection), ViewState, coordinators, testing, anti-patterns |
| references/viper.md | VIPER: 5 layers, ownership chain, module assembly, testing, anti-patterns |
| references/accessibility-audit.md | Structured audit: P0/P1/P2 findings, patch-ready fixes, manual test checklist |
| references/keyboard.md | Keyboard-safe layout: keyboardLayoutGuide + the iOS 13–14 curve-matched fallback |
| references/interface-builder.md | XIB runtime-diagnosis, the XIB↔Swift split (cgColor/UDRA), shared-cell hygiene |
| references/swiftui-bridging.md | UIViewRepresentable/UIViewControllerRepresentable/gesture/hosting interop recipes |
| references/pencilkit-canvas.md | PencilKit, Apple Pencil, drawing-canvas correctness, save/restore matrix |
| references/pointer-and-focus.md | iPadOS/macOS pointer effects + the focus engine (iPad/macOS/tvOS, Siri Remote) |
| references/ipad-multiwindow.md | UIScene multi-window, Stage Manager, size-class adaptation, column sizing |
| references/windows-and-overlays.md | Global blocking HUD via a dedicated UIWindow (above sheets/alerts) |
Bundled tools
scripts/xib_runtime_risk_scan.py — heuristic static analyzer (stdlib-only)
that flags the three XIB runtime-collapse patterns ibtool can't catch
(.fill+fixed-sibling+multiline collapse, multiline label with a fixed-height
constraint, image/color referenced but missing from <resources>). Run it
before manual XIB debugging to narrow the search. See references/interface-builder.md.