Sample CodeiOS, iPadOS, Mac Catalyst, macOS, visionOSReviewed 2026-07-21View on Apple Developer

Enriching your text in text views

At a glance

Item Summary
Purpose Demonstrates TextKit line numbers, collapsible sections, attachments, exclusion paths, and list markers.
App architecture SwiftUI owns navigation; thin representables construct platform views, and each platform container owns one independent TextKit demonstration.
Main patterns Adapter layer, compile-time platform abstraction, feature slices, delegate-driven filtering, and attachment view providers.
Project style Cross-platform SwiftUI shell around AppKit/UIKit TextKit views; feature behavior stays in one file per demonstration.

Project structure

TextKitAndTextViewSampleApp/
├── SwiftUI/
│   ├── TextKitAndTextViewSampleApp.swift
│   ├── ContentView.swift
│   ├── Representables.swift
│   └── Platform.swift
├── LineNumberingView.swift
├── SectionCollapsingView.swift
├── InlineAttachmentsView.swift
├── TextAttachmentView.swift
├── ExclusionPathView.swift
├── TextListView.swift
└── Assets/

Structure observations

  • SwiftUI/ is a navigation/adaptation layer, not the TextKit implementation layer.
  • Every demonstration file contains its container plus narrowly related private helper views, storage extensions, or attachment providers.
  • Platform.swift centralizes AppKit/UIKit typealiases and the small layout differences shared by container views.

Overall architecture

Reference code

TextKitAndTextViewSampleApp/SwiftUI/Representables.swift:18 — compile-time adapters construct the same feature container for AppKit or UIKit.

#if os(macOS)
private struct LineNumberingRepresentable: NSViewRepresentable {
    func makeNSView(context: Context) -> LineNumberingContainerView { LineNumberingContainerView() }
    func updateNSView(_ nsView: LineNumberingContainerView, context: Context) {}
}
#else
private struct LineNumberingRepresentable: UIViewRepresentable {
    func makeUIView(context: Context) -> LineNumberingContainerView { LineNumberingContainerView() }
    func updateUIView(_ uiView: LineNumberingContainerView, context: Context) {}
}
#endif

Interpretation

The representables are construction adapters only: they carry no domain state and have empty update methods. TextKit objects remain owned by reference-type platform views, which is the layer receiving layout and delegate callbacks.

Ownership and state

Ownership evidence

TextKitAndTextViewSampleApp/SectionCollapsingView.swift:11 — the container owns both views and uses a weak closure capture to avoid a container–gutter cycle.

class SectionCollapsingContainerView: PlatformContainerView {
    // ...
}
Owner State Relationship Mutation authority
ContentView Selected sidebar item SwiftUI @State List selection binding
Each container view Text view plus companion gutter/control Creates and retains Initialization and feature callbacks
Specialized text view Paragraph cache, collapsed offsets, layout-pass entries Owns TextKit-derived state TextKit callbacks/toggle methods
Attachment view/provider Player and rendered attachment view Provider creates; text view manages reuse Attachment lifecycle

Class and protocol design

Type family Responsibility Design note
SwiftUI feature views/representables Select and construct a native feature view Thin adapters; no coordinators needed
PlatformContainerView Normalize text-view embedding between AppKit and UIKit Small inheritance-based platform seam
Feature container views Load assets and assemble TextKit plus companion UI One owner per demonstration
Specialized text/gutter views Respond to viewport layout or content enumeration Private helpers protect feature invariants
Attachment subclasses/providers Supply interactive/animated inline views Framework extension points for attachment lifecycle

No app-defined protocol exists. Protocol-oriented design is expressed through framework contracts such as UIViewRepresentable/NSViewRepresentable, NSTextContentStorageDelegate, and UIContentView-style TextKit provider APIs.

Access control

Symbol Access Verified effect Rationale
Platform representables private Only public-facing SwiftUI wrappers in the same file construct them. Hides bridge mechanics from feature consumers.
Specialized text/gutter/player views private Helpers cannot be coupled from other files. Their state is meaningful only inside one demonstration.
Container textView/gutterView pairs fileprivate in line/collapse samples Same-file helper classes can call back across type boundaries. Narrower than module access while supporting a file-scoped feature slice.
Platform typealiases and containers implicit internal All feature files share them inside the target. Cross-file platform vocabulary, not exported API.
selection @State private Only ContentView controls navigation state. SwiftUI view-local source of truth.

Reference code

TextKitAndTextViewSampleApp/LineNumberingView.swift:10fileprivate exposes only the two collaborators required by same-file layout helpers.

class LineNumberingContainerView: PlatformContainerView {
    // ...
}

Logic ownership and placement

Logic Owner or file Why it belongs there
Navigation/feature selection ContentView Pure SwiftUI presentation state.
UIKit/AppKit construction Representables.swift Boundary between value views and native reference views.
Platform layout differences Platform.swift Avoids scattering conditional aliases and scroll setup.
Visible line indexing/gutter drawing LineNumberingView.swift One file owns cache, viewport callback, and rendering.
Paragraph filtering/collapse state SectionCollapsingView.swift NSTextContentStorageDelegate needs direct access to collapsed offsets.
Attachment reuse/playback Attachment feature files Lifecycle follows TextKit attachment providers.

Design patterns

Pattern Source evidence Purpose or tradeoff
SwiftUI adapter layer TextKitAndTextViewSampleApp/SwiftUI/Representables.swift:12 Hosts imperative TextKit views without moving their state into SwiftUI.
Compile-time platform abstraction TextKitAndTextViewSampleApp/SwiftUI/Platform.swift:8 Shares feature code while retaining native UIKit/AppKit types.
File-scoped feature slice TextKitAndTextViewSampleApp/LineNumberingView.swift:10 Keeps owner and private collaborators together.
Delegate filtering TextKitAndTextViewSampleApp/SectionCollapsingView.swift:140 Hides body paragraphs at enumeration time rather than rewriting source text.
Provider/reuse policy TextKitAndTextViewSampleApp/InlineAttachmentsView.swift:22 Lets TextKit manage expensive attachment views across edits and scrolling.

Naming conventions

  • Public-facing feature names pair ...View with ...ContainerView and private ...Representable bridges.
  • PlatformView, PlatformTextView, and related aliases make cross-platform intent explicit.
  • Helpers describe visible roles: GutterView, DisclosureGutterView, and AnimatedAttachmentViewProvider.
  • Mutating methods use concrete outcomes such as toggleSection, rebuild, and setListMarkerStyle.

Architecture takeaways

  • Keep SwiftUI representables thin when the native view has a rich callback-driven lifecycle.
  • Use file-scoped feature slices to permit collaboration without widening helpers to the whole module.
  • Centralize only real platform differences; leave feature logic shared and native.
  • Model layout-derived UI, such as gutters, as a collaborator owned beside the text view.

Source map

Source file Relevant symbols
TextKitAndTextViewSampleApp/SwiftUI/ContentView.swift Navigation and selection
TextKitAndTextViewSampleApp/SwiftUI/Representables.swift SwiftUI/native adapters
TextKitAndTextViewSampleApp/SwiftUI/Platform.swift AppKit/UIKit abstraction
TextKitAndTextViewSampleApp/LineNumberingView.swift Viewport cache and gutter
TextKitAndTextViewSampleApp/SectionCollapsingView.swift Content filtering and collapse state
TextKitAndTextViewSampleApp/InlineAttachmentsView.swift Animated attachment provider
TextKitAndTextViewSampleApp/TextAttachmentView.swift Expandable attachment
TextKitAndTextViewSampleApp/ExclusionPathView.swift Exclusion geometry
TextKitAndTextViewSampleApp/TextListView.swift List marker editing