Sample CodemacOSReviewed 2026-07-21View on Apple Developer

Organize Your User Interface with a Stack View

At a glance

Item Summary
Purpose Build a vertically stacked inspector whose independent sections expand, collapse, animate, and restore state.
Architecture Three small protocols compose a host, header, and body into StackItemContainer; concrete view controllers supply each role.
Main owner The root ViewController loads section controllers and inserts their header/body views into NSStackView.

Project structure

InfoBarStackView/
├── StackView.swift
├── ViewController.swift
├── BaseViewController.swift
├── HeaderViewController.swift
├── {Form,Table,Collection,Other}ViewController.swift
└── WindowController.swift

StackView.swift holds the reusable protocol vocabulary and default behavior; feature controllers provide concrete content.

Overall architecture

Reference code

InfoBarStackView/ViewController.swift:27 — the host composes each protocol-backed section into arranged views.

    private func addViewController(withIdentifier identifier: String) {
        // ...
    }

Ownership and state

Ownership evidence

InfoBarStackView/BaseViewController.swift:28 — every body lazily creates the container that pairs it with a header.

class BaseViewController: NSViewController, StackItemBody {
    // ...
    // MARK: - StackItemContainer
    // ...
}

The root controller owns visual arrangement. Each body controller owns its lazy container and original height. The container owns the disclosure state and role references; the header carries a closure that sends disclosure intent back to the host.

Class and protocol design

Type Responsibility
StackItemHost Toggle containers and coordinate body/header state.
StackItemHeader Expose a header controller, disclosure callback, and visual state update.
StackItemBody Expose a body controller and show/hide behavior.
StackItemContainer Pair header and body and store disclosure state.
BaseViewController Common body behavior, height state, and restoration.
Concrete body controllers Table, collection, form, or other section content.

Protocol extensions provide the default orchestration and constrain header/body adapters to NSViewController where needed.

Access control

Boundary Effect and rationale
private addViewController Only the root composition flow can insert sections into the stack.
Protocols and containers are implicit internal They are reusable across the app target but not presented as a public framework.
Body state is target-visible Protocol default implementations and concrete subclasses need height and container access.
Restored state passes through controller methods AppKit’s restoration contract remains the external boundary.

InfoBarStackView/ViewController.swift:27 is the explicit private composition method; InfoBarStackView/StackView.swift:13 shows the internal protocol surface.

Logic ownership and placement

Logic Owner
Disclosure state transition StackItemHost default implementation
Height animation StackItemBody default implementation
Header visual update Concrete StackItemHeader
Storyboard composition and arranged-subview order Root ViewController
Save/restore disclosure state BaseViewController
Window recreation WindowController

Design patterns

Pattern Evidence Purpose
Protocol composition InfoBarStackView/StackView.swift:13 Decouples host, header, and body roles.
Container object InfoBarStackView/StackView.swift:122 Carries paired roles and their shared state.
Template method via base class InfoBarStackView/BaseViewController.swift:17 Lets subclasses supply titles while reusing lifecycle behavior.
Closure callback InfoBarStackView/ViewController.swift:36 Sends header intent to the host without a concrete header dependency.
State restoration InfoBarStackView/BaseViewController.swift:55 Persists each section’s disclosure state.

Naming conventions

  • Protocol names describe roles rather than implementations: StackItemHost, StackItemHeader, and StackItemBody.
  • StackItemContainer states that it composes roles; BaseViewController signals subclass reuse.
  • Concrete content controllers use domain-neutral view type names such as FormViewController and TableViewController.

Architecture takeaways

  • Use narrow role protocols when composition matters more than concrete controller types.
  • Store shared header/body state in a container, not in NSStackView itself.
  • Put reusable show/hide behavior in constrained protocol extensions.
  • Keep storyboard loading and arranged-subview order in one composition owner.

Source map

Source Role
InfoBarStackView/StackView.swift:13 Protocol roles and container
InfoBarStackView/ViewController.swift:10 Stack composition owner
InfoBarStackView/BaseViewController.swift:10 Reusable body and restoration
InfoBarStackView/WindowController.swift:10 Window restoration