Implementing Peek and Pop
At a glance
| Item |
Summary |
| Purpose |
Compares storyboard and code registration for legacy Peek and Pop, including preview quick actions. |
| App architecture |
A base table controller owns catalog behavior; two subclasses isolate storyboard-versus-code preview setup, and an injected detail controller mutates the selected model. |
| Main patterns |
Template Method inheritance, preview/commit, model injection, observer notifications, and model-owned change events. |
| Project style |
Small storyboard app with a dedicated Models/ folder and deliberately parallel feature variants. |
Project structure
PeekPopNavigation/
├── ColorsViewControllerBase.swift
├── ColorsViewControllerCode.swift
├── ColorsViewControllerStoryboard.swift
├── ColorItemViewController.swift
├── Models/
│ ├── ColorData.swift
│ ├── ColorItem.swift
│ └── Notifications.swift
└── Base.lproj/Main.storyboard
Structure observations
- The base controller contains all table, navigation, and notification behavior so each variant shows only its integration difference.
ColorsViewControllerStoryboard is intentionally empty; storyboard configuration is the implementation.
- Model events are named in
Notifications.swift, separate from the mutable model types that emit them.
Overall architecture
flowchart LR
Storyboard["Storyboard variant"] --> Base["ColorsViewControllerBase"]
Code["ColorsViewControllerCode"] --> Base
Base --> Data["ColorData"]
Base --> Table["Color list"]
Code --> PreviewDelegate["UIViewControllerPreviewingDelegate"]
PreviewDelegate --> Preview["ColorItemViewController preview"]
Preview -->|commit| Nav["Navigation controller push"]
Base -->|normal segue| Preview
Data --> Preview
Item["ColorItem"] --> Preview
Preview --> QuickActions["Star / Delete preview actions"]
QuickActions --> Item
QuickActions --> Data
Reference code
PeekPopNavigation/ColorsViewControllerCode.swift:25 — the code variant builds the preview with the same ColorData and ColorItem references used by the list, then commits that configured controller.
func previewingContext(_ previewingContext: UIViewControllerPreviewing,
viewControllerForLocation location: CGPoint) -> UIViewController? {
guard let indexPath = tableView.indexPathForRow(at: location),
let cell = tableView.cellForRow(at: indexPath) else { return nil }
previewingContext.sourceRect = cell.frame
guard let viewController = storyboard?.instantiateViewController(
withIdentifier: "ColorItemViewController") as? ColorItemViewController
else { preconditionFailure("Expected a ColorItemViewController") }
viewController.colorData = colorData
viewController.colorItem = colorData.colors[indexPath.row]
return viewController
}
func previewingContext(_ previewingContext: UIViewControllerPreviewing,
commit viewControllerToCommit: UIViewController) {
navigationController?.pushViewController(viewControllerToCommit, animated: true)
}
Interpretation
Preview is not a copy of feature state. The preview and eventual committed controller share the original object references, so quick actions immediately affect the same catalog observed by the table screen.
Ownership and state
classDiagram
ColorsViewControllerBase *-- ColorData : creates one per instance
ColorData *-- ColorItem : owns array
ColorsViewControllerBase --> NotificationCenter : observes
ColorItem --> NotificationCenter : posts updated
ColorData --> NotificationCenter : posts deleted
ColorsViewControllerCode --|> ColorsViewControllerBase
ColorsViewControllerStoryboard --|> ColorsViewControllerBase
ColorItemViewController o-- ColorData : injected reference
ColorItemViewController o-- ColorItem : injected reference
ColorItem ..|> Equatable
Ownership evidence
PeekPopNavigation/Models/ColorItem.swift:10 — each mutable property emits a model event; the owning data array remains in ColorData.
class ColorItem {
// ...
}
| Owner |
State |
Relationship |
Mutation authority |
| Each base-controller instance |
Its own ColorData |
Creates and retains |
Detail actions through injected reference |
ColorData |
Ordered ColorItem array |
Owns catalog |
delete(_:) |
ColorItem |
Name, color, starred flag |
Reference model |
Detail normal/preview actions |
ColorItemViewController |
Selected data/item references |
Injected, not copied |
UI actions |
Class and protocol design
| Type |
Responsibility |
Design note |
ColorsViewControllerBase |
Table source, normal segue, model-event handling |
Shared template for both integration variants |
ColorsViewControllerCode |
Register previewing and implement preview/commit callbacks |
Focused framework adapter subclass |
ColorsViewControllerStoryboard |
Mark storyboard-configured variant |
Empty by design |
ColorItemViewController |
Present/mutate one color and expose preview actions |
Receives both item and owning collection |
ColorData / ColorItem |
Own catalog and mutable item state |
Reference models broadcast changes |
There is no app-defined protocol. The code variant conforms directly to the UIKit previewing delegate; the base-class seam is inheritance because the sample compares two setup mechanisms around identical behavior.
Access control
| Symbol group |
Access |
Verified effect |
Rationale |
| All app types, properties, and methods |
implicit internal |
Any code in the sample target can access them. |
The source declares no private, fileprivate, or public members. |
colorData |
implicit internal let |
Subclasses and detail injection can read the stable container reference. |
Shared behavior crosses the base/subclass boundary. |
| Detail model references |
implicit internal optionals |
Segue and preview code inject them across files. |
Required composition seam inside the target. |
| Notification names |
implicit internal static let |
Models and observers share typed names. |
Target-wide event vocabulary. |
Reference code
PeekPopNavigation/ColorsViewControllerBase.swift:15 — the base exposes its stable model container to subclasses rather than widening anything to a public framework API.
class ColorsViewControllerBase: UITableViewController {
// ...
}
Logic ownership and placement
| Logic |
Owner |
Why it belongs there |
| Common table and navigation behavior |
Base controller |
Shared by both integration variants. |
| Code-based preview/commit |
Code subclass |
Isolates the API the sample is comparing. |
| Storyboard preview setup |
Storyboard resource/empty subclass |
Configuration itself is the demonstration. |
| Star/delete commands |
Detail controller |
Same commands serve normal and preview UI. |
| Change/delete notifications |
ColorItem / ColorData |
Event originates where mutation occurs. |
Design patterns
| Pattern |
Source evidence |
Purpose or tradeoff |
| Template Method base controller |
PeekPopNavigation/ColorsViewControllerBase.swift:15 |
Removes unrelated table code from the two preview variants. |
| Preview/commit |
PeekPopNavigation/ColorsViewControllerCode.swift:25 |
Configures once, then pushes the same controller on commit. |
| Dependency injection |
PeekPopNavigation/ColorsViewControllerBase.swift:58 |
Gives detail access to the selected item and deletion owner. |
| Observer notifications |
PeekPopNavigation/Models/ColorData.swift:27 |
Refreshes list UI after mutations from preview actions. |
Naming conventions
Base, Code, and Storyboard suffixes make the comparison structure explicit.
ColorData names the collection owner; ColorItem names one mutable entity.
- Notifications use past-tense events:
colorItemUpdated and colorItemDeleted.
previewingContext names are inherited from UIKit; domain actions remain toggleStar and delete.
Architecture takeaways
- Factor shared feature behavior away from alternative integration mechanisms when teaching or testing platform APIs.
- Inject the same model reference into preview and committed presentation when actions must have immediate effect.
- Emit change events from mutation owners, but scope observers by object identity when multiple catalogs exist.
- Internal access is sufficient for an app target; absence of access modifiers should not be described as a public API.
Source map
| Source file |
Relevant symbols |
PeekPopNavigation/ColorsViewControllerBase.swift |
Shared list, segue, and observers |
PeekPopNavigation/ColorsViewControllerCode.swift |
Code preview/commit adapter |
PeekPopNavigation/ColorsViewControllerStoryboard.swift |
Storyboard variant marker |
PeekPopNavigation/ColorItemViewController.swift |
Detail and preview quick actions |
PeekPopNavigation/Models/ColorData.swift |
Catalog owner and deletion |
PeekPopNavigation/Models/ColorItem.swift |
Mutable item and update events |
PeekPopNavigation/Models/Notifications.swift |
Typed notification names |