Visitor
Visitor adds an operation across a fixed set of element types. In Swift, an enum and exhaustive switch often provide the same benefit with less ceremony.
When it helps in iOS
A note editor stores headings, paragraphs, and checkboxes. Exporting plain text must handle every block while keeping rendering code outside the UI components.
Original example: visit document blocks
import Foundation
enum NoteBlock {
case heading(String)
case paragraph(String)
case checkbox(title: String, isChecked: Bool)
}
struct PlainTextExportVisitor {
func visit(_ block: NoteBlock) -> String {
switch block {
case .heading(let text):
return "# \(text)"
case .paragraph(let text):
return text
case .checkbox(let title, let checked):
return "[\(checked ? "x" : " ")] \(title)"
}
}
func export(_ blocks: [NoteBlock]) -> String {
blocks.map(visit).joined(separator: "\n")
}
}
let note: [NoteBlock] = [.heading("Trip"), .checkbox(title: "Pack charger", isChecked: true)]
let output = PlainTextExportVisitor().export(note)The visitor owns one operation over all block variants. Adding a new block case makes the compiler point to export operations that need updating.
Production decisions
This enum form works well when block types change rarely and new operations, such as Markdown and accessibility summaries, are added often. If third-party modules must add new block types, a classic protocol-based visitor or plugin registry may fit better. Escape user text when exporting to HTML or Markdown.
Where the operation lives
NoteBlock lists the element variants; PlainTextExportVisitor owns the export operation. visit(_:) uses an exhaustive switch to format each case, and export(_:) applies it to a document. Adding a new block variant makes the compiler identify the visitors that must handle it. That is the value of this Swift form of Visitor: operations stay separate from editing views while the set of element types is explicit.
From example to note sharing
The editor stores a sequence of blocks. When the user taps Share, the view model passes blocks to an exporter visitor, writes the returned text to a file, and presents a share sheet. A Markdown visitor or accessibility-summary visitor can be added without putting export code into the block views. For rich text or HTML, escape user text and preserve ordering, list nesting, and attachments deliberately.
Failure modes and verification
Test every case, multiline text, empty documents, and special characters. An enum visitor works best when new operations are frequent and new block types are rare. If external plugins must add arbitrary block types, the closed enum is a limitation; a protocol-based double-dispatch visitor or renderer registry may fit. Do not use Visitor just to avoid a single small switch that has no reuse.