Protocols and Extensions for App Models
Share a naming capability between models
A contact and a saved place both need a navigation label. Define the small capability they share, implement a derived label once, and use it without an inheritance hierarchy.
Start with the small worked operation, follow its decisions, then open the matching complete Xcode checkpoint. It includes the exact source used for the screenshot. The examples use local fixtures so you can inspect behavior without an account or server.
Reuse one capability across unrelated models
Contacts and saved places are different app concepts, but both may provide a name for a navigation label. A protocol can describe that shared capability without forcing the models into an inheritance hierarchy. The extension can implement behavior using only what the protocol guarantees.
protocol AccessibleNamed { var name: String { get } }
extension AccessibleNamed {
var spokenLabel: String { "Open \(name)" }
}
struct Contact: AccessibleNamed { let name: String }
struct Place: AccessibleNamed { let name: String }
assert(Contact(name: "Maya").spokenLabel == "Open Maya")
assert(Place(name: "Library").spokenLabel == "Open Library")The extension cannot assume that every conformer has an address or phone number: neither property is in the contract. The get requirement permits reading a String; it does not demand a stored mutable var. A conformer can supply a let property or a computed getter.
Make the boundary explicit at a call site
func navigationLabel(for item: some AccessibleNamed) -> String {
item.spokenLabel
}
assert(navigationLabel(for: Place(name: "Park")) == "Open Park")The caller needs the naming capability, not a particular concrete model. This is a useful abstraction when more than one meaningful type shares the rule. Do not create a protocol for every struct by reflex. Also distinguish a protocol requirement from an extension-only helper when designing overridable behavior; dispatch through abstractions deserves a deliberate contract, not an assumption based on a similarly named method.
Run the complete scenario on iPhone

The interface below calls the operations discussed above and presents their results. This is a dedicated example for this lesson, not the greeting app used in the first revision. Replace ContentView.swift in the downloadable project with this complete source if reproducing it by hand.
import SwiftUI
protocol AccessibleNamed { var name: String { get } }
extension AccessibleNamed { var spokenLabel: String { "Open \(name)" } }
struct Contact: AccessibleNamed { let name: String }
struct Place: AccessibleNamed { let name: String }
struct ContentView: View {
var body: some View {
VStack(alignment: .leading, spacing: 20) {
Text("Shared naming rule").font(.title).bold()
Text("Contact").font(.headline)
Text(Contact(name: "Maya").spokenLabel)
Text("Place").font(.headline)
Text(Place(name: "Library").spokenLabel)
}.padding(24)
}
}
#Preview { ContentView() }
Download this complete checkpoint project. The code above replaces ContentView.swift in this project; its app entry point is already included.
Apply the idea to a new case
Add a Playlist conformer with the name Evening. Reuse the label without copying its formatting.
Worked answer
Playlist declares name: String and AccessibleNamed conformance. Its spokenLabel becomes Open Evening through the existing extension. Applying the label to an actual accessible control is a separate UI integration step.
This exercise is a proposed change; the screenshot shows the supplied baseline. Predict the outcome before running and restore the baseline when comparing against the capture.
Explain the behavior
Choose the explanation that follows from the worked example.
What to take into the next lesson
You defined a readable naming contract, derived behavior in an extension and used it across unrelated models. Next, report and recover from expected failures.
Reaching the recap and completing the quizzes are separate milestones.