Integrating accessibility into your app
At a glance
| Item | Summary |
|---|---|
| Purpose | Catalog AppKit accessibility techniques for standard and custom controls, text, images, tables, layout areas, and rotors. |
| Architecture | A split-view shell dynamically loads many independent example controllers from storyboards. |
| Main pattern | Selection metadata drives controller creation; each feature folder contains a self-contained accessibility demonstration. |
| Boundary | One macOS app target with Swift, Objective-C, and Metal examples; it is an example gallery, not one domain application. |
Project structure
AccessibilityUIExamples/
├── Application/ # catalog, split shell, dynamic detail host
├── Buttons/ Text/ Images/
├── Checkbox/ Slider/ Stepper/ Switches/
├── Table/ Outline/ LayoutArea/
├── CustomRotors/
└── TransientUI/ SearchField/ RadioButtons/
Folder names are the architectural index: each is a focused demo with its own controller and custom view.
Overall architecture
flowchart LR
App["AppDelegate"] --> Split["SplitViewController"]
Split --> Main["MainViewController"]
Main --> Catalog["[Example] metadata"]
Main --> Split
Split --> Detail["DetailViewController"]
Detail --> Storyboard["Feature storyboard"]
Storyboard --> Demo["Independent example controller + view"]
Demo --> AppKit["NSAccessibility roles / protocols"]
Reference code
AccessibilityUIExamples/Application/DetailViewController.swift:35 — metadata selects and embeds a feature controller (abridged).
let storyboard = NSStoryboard(
name: detailItemRecord.viewControllerIdentifier,
bundle: nil
)
let controller = storyboard.instantiateController(
withIdentifier: detailItemRecord.viewControllerIdentifier
) as? NSViewController
insertChild(controller, at: 0)
view.addSubview(controller.view)Ownership and state
classDiagram
SplitViewController *-- MainViewController
SplitViewController *-- DetailViewController
MainViewController *-- Example : examplesArrayBacking
MainViewController o-- MainViewControllerDelegate : weak
DetailViewController *-- NSViewController : current child
CustomControl *-- AccessibilityState : feature-local
Ownership evidence
AccessibilityUIExamples/Application/SplitViewController.swift:26 — the split controller wires and retains the two shell children.
mainViewController = splitViewItems[0].viewController as? MainViewController
mainViewController.delegate = self
self.detailViewController = splitViewItems[1].viewController as? DetailViewController
func didChangeExampleSelection(...) {
detailViewController.detailItemRecord = selection
}The shell owns the current example lifecycle. Feature controls own only their drawing, input, and accessibility state; there is no shared domain store.
Class and protocol design
MainViewControllerDelegate: AnyObject is the app-defined selection boundary at AccessibilityUIExamples/Application/MainViewController.swift:263. Feature types mostly adopt framework contracts directly—for example, CustomSliderView: NSView, NSAccessibilitySlider at AccessibilityUIExamples/Slider/CustomSliderView.swift:18. Custom rotor views add small delegate protocols when they must ask a controller for elements.
Access control
| Symbol | Access | Rationale |
|---|---|---|
| Catalog table callbacks | public |
Explicit witnesses for AppKit data-source/delegate behavior (AccessibilityUIExamples/Application/MainViewController.swift:62). |
| Catalog builder methods | fileprivate |
Only the same file assembles its metadata sections (AccessibilityUIExamples/Application/MainViewController.swift:98). |
Slider LayoutInfo and geometry helpers |
fileprivate |
Its same-file extensions need access while other files do not (AccessibilityUIExamples/Slider/CustomSliderView.swift:22). |
| View-local flags | private in newer examples |
Prevent external mutation of control implementation details. |
| Most types | internal default | They participate only in the app target and storyboard lookup. |
Here fileprivate is purposeful: a base declaration and same-file extensions share helpers. public does not make this a library; it is used for framework-facing methods.
Logic ownership and placement
| Logic | Owner | Placement reason |
|---|---|---|
| Example registry | MainViewController |
It populates the catalog and maps names to storyboard identifiers. |
| Selection routing | SplitViewController |
It coordinates master and detail children. |
| Dynamic child replacement | DetailViewController |
It owns the detail host area. |
| Accessibility behavior | Each custom control/view | The view knows its geometry and interaction semantics (AccessibilityUIExamples/CustomRotors/ElementView/CustomRotorsContainerView.swift:34). |
Design patterns
| Pattern | Evidence | Purpose |
|---|---|---|
| Example catalog | Example metadata + storyboard identifiers |
Makes dozens of techniques independently discoverable. |
| Split-view coordinator | Shell routes selection into detail | Centralizes navigation without coupling feature examples. |
| Delegate | Main-to-split selection callback | Avoids the list owning detail presentation. |
| Framework protocol adapter | Custom controls adopt accessibility protocols | Adds semantics to existing custom drawing code. |
Naming conventions
- Feature folders and controllers share nouns (
Slider/CustomSliderViewController). - Custom implementations use
Customor a precise control role, while shell types useMain,Detail, andSplit. - Delegate protocols name the producer (
MainViewControllerDelegate) and callbacks begin withdid....
Architecture takeaways
- Read the archive as a host plus independent recipes, not a monolithic production architecture.
- Use the shell to own navigation and feature controllers to own their accessibility semantics.
- Same-file
fileprivatehelpers can support extension-based organization without widening target-wide access. - Mixed Swift/Objective-C files are parallel demonstrations, not duplicated layers of one subsystem.
Source map
| Source | Role |
|---|---|
AccessibilityUIExamples/Application/AppDelegate.swift:10 |
macOS entry point |
AccessibilityUIExamples/Application/MainViewController.swift:27 |
Catalog construction |
AccessibilityUIExamples/Application/SplitViewController.swift:40 |
Selection routing |
AccessibilityUIExamples/Application/DetailViewController.swift:16 |
Child replacement |
AccessibilityUIExamples/Slider/CustomSliderView.swift:226 |
Accessibility slider implementation |
AccessibilityUIExamples/CustomRotors/ElementView/CustomRotorsContainerView.swift:51 |
Feature-local delegate protocol |