Sample CodemacOSReviewed 2026-07-21View on Apple Developer

Integrating a Toolbar and Touch Bar into Your App

At a glance

Item Summary
Purpose Offer the same font-size and font-style commands through an NSToolbar and an NSTouchBar.
Architecture A content view controller owns the text view; one window controller owns command logic and constructs both command surfaces.
Shared state currentFontSize is the binding point between toolbar controls, the touch-bar slider, and text mutations.

Project structure

ToolbarSample/
├── AppDelegate.swift
├── ViewController.swift
├── WindowController.swift
└── WindowController+TouchBar.swift

The touch-bar extension keeps a secondary framework surface separate while reusing the window controller’s formatting commands and state.

Overall architecture

Reference code

ToolbarSample/WindowController.swift:86 — command logic reaches the single content text view through the window graph.

func contentTextView() -> NSTextView {
    let viewController = self.contentViewController as? ViewController
    return viewController!.textView
}

Ownership and state

Ownership evidence

ToolbarSample/WindowController.swift:17 — the window controller holds the shared control state and toolbar objects.

class WindowController: NSWindowController, NSToolbarDelegate {
    // ...
}

The storyboard owns initial controller and outlet construction. WindowController is the mutation authority for formatting and control synchronization; ViewController owns the actual text-view outlet and only customizes text-view delegate behavior.

Class and protocol design

Type Responsibility Contract
WindowController Command state, text formatting, toolbar factory, printing NSToolbarDelegate
WindowController extension Touch-bar factory and item actions NSTouchBarDelegate
ViewController Hold the editable text view and suppress system text items NSTextViewDelegate
AppDelegate Enable application-wide touch-bar customization UI NSApplicationDelegate

No app-defined protocol is needed because both surfaces call the same concrete command owner through target/action and binding.

Access control

Boundary Effect and rationale
private toolbar identifier extension Keeps identifier constants file-scoped and prevents unrelated files from depending on them.
private touch-bar customization identifier extension Provides the same namespace boundary for the touch-bar file.
Implicit internal controllers and commands Supports storyboard and cross-file extension access inside the app target only.
@objc dynamic currentFontSize Exposes the property to Cocoa binding/KVO; this is runtime visibility, not public API.

The two identifier boundaries are visible at ToolbarSample/WindowController.swift:11 and ToolbarSample/WindowController+TouchBar.swift:10.

Logic ownership and placement

Logic Owner
Font conversion and selection handling WindowController
Toolbar item factory and allowed/default sets WindowController.swift
Touch-bar item factory WindowController+TouchBar.swift
Text-system touch-bar filtering ViewController
App-wide customization opt-in AppDelegate

Design patterns

Pattern Evidence Purpose
Shared command controller ToolbarSample/WindowController.swift:94 One formatting implementation serves two UI surfaces.
Delegate factory ToolbarSample/WindowController.swift:281 Creates toolbar items from identifiers.
Target/action ToolbarSample/WindowController+TouchBar.swift:57 Routes controls to the window command owner.
Cocoa binding ToolbarSample/WindowController+TouchBar.swift:83 Synchronizes the touch-bar slider with shared size state.
Capability extension ToolbarSample/WindowController+TouchBar.swift:20 Isolates touch-bar integration without duplicating the controller.

Naming conventions

  • Surface-specific code uses a +TouchBar filename while retaining the owning type name.
  • Commands describe user intent: setTextViewFontSize, setTextViewFont, and changeFontSizeBySlider.
  • Identifier names mirror controls: fontSize, fontStyle, popover, and popoverSlider.

Architecture takeaways

  • Route multiple command surfaces through one mutation owner.
  • Separate framework-specific factories while sharing state and domain commands.
  • Use file-private identifier namespaces to avoid string scattering.
  • For a larger app, inject a formatting command object rather than reaching through contentViewController; this sample stays deliberately controller-centric.

Source map

Source Role
ToolbarSample/WindowController.swift:17 Shared command and toolbar owner
ToolbarSample/WindowController+TouchBar.swift:20 Touch-bar factory
ToolbarSample/ViewController.swift:10 Text-view owner
ToolbarSample/AppDelegate.swift:14 Customization opt-in