Appendix N: IntelligenceDemo (Shop Manual)
Status: Live as a proof-of-concept reference app. GPL v3. Public repo at github.com/fluhartyml/IntelligenceDemo. Build-Along chapter: Part VII Build-Along 08. IntelligenceDemo is the book's smallest possible OCR utility: two Swift files, three imports, one screen. Pick a photo, the Vision framework extracts the text, the text appears with system text-selection enabled. Books 06, 12, 14, and 18 all reach for this app as their PhotosPicker / Vision / clipboard / inline-error-feedback example. ScanKeeper (Appendix U) is the production evolution of the same idea; this demo is the chapter-teaching baseline.
What it is
One screen. The user taps PhotosPicker, picks a photo from their library, and the Vision framework runs VNRecognizeTextRequest against the image. The recognized text appears below the image with .textSelection(.enabled), which gives the user long-press / select-all / copy without any custom menu code. On recognition failure, an inline error string ("Recognition failed: ...") appears in the same text slot. That's the entire app.
Architecture overview
Two files. The smallest scale anywhere in the roster.
- App entry:
IntelligenceDemoApp.swift—@mainscene. - The whole app:
ContentView.swift— imports SwiftUI, PhotosUI, Vision. Four@Stateproperties (pickedItem,pickedImage,extractedText,isProcessing), two private async methods (load(item:),recognizeText(in:)), and the view body.
The flow
- User taps the
PhotosPickerbound topickedItem. - On selection, the
onChange(of: pickedItem)handler callsload(item:), which asks thePhotosPickerItemfor itsTransferabledata and decodes it into aUIImage. - The loaded
UIImageis shown above the result area;isProcessingflips on. recognizeText(in: image)wraps aVNImageRequestHandler.perform(...)call indo/catch. On success, the recognized strings get joined intoextractedText; on a thrown error,extractedTextbecomes"Recognition failed: \(error.localizedDescription)".- The result
Textview has.textSelection(.enabled)— the user can long-press, select, and copy with noUIPasteboardcode from the app.
Why it's so small (the teaching point)
The whole app is two files because three Apple-provided pieces do everything:
PhotosPickerfrom PhotosUI. The user-mediated picker pattern: the system shows the photo browser, the app receives only the picked item. NoNSPhotoLibraryUsageDescriptionstring required. No PhotoKit boilerplate.- Vision framework's
VNRecognizeTextRequest. On-device OCR. No model training, no Core ML wiring, no third-party library.VNImageRequestHandler.perform([request])returns recognized text in a few lines. .textSelection(.enabled). SwiftUI's one-modifier handoff to the system text-selection UI. Long-press / select-all / copy / share all come for free.
The chapter's point: the smallest possible OCR utility doesn't need a state machine, a service layer, or a manager class. It needs four @State properties and two async methods.
The inline-error pattern (Book 18 reference)
Book 18 (Error Handling and Result Type) reaches for this app's recognizeText(in:) as the textbook "the error IS the result" example. The method signature is async -> String, not async throws or async -> Result. On failure, the returned string is the error message prefixed with "Recognition failed: ":
private func recognizeText(in image: UIImage) async -> String {
do {
// ... VNImageRequestHandler.perform(...) ...
return recognized.joined(separator: "\n")
} catch {
return "Recognition failed: \(error.localizedDescription)"
}
}
The error surface is inline with the result — no alert, no separate error state machine — because for a one-photo OCR utility, the error IS the result. The user wants to see what happened in the same place the text would have appeared. Book 18 contrasts this with CryoKit's structured-error approach (Appendix B); the comparison clarifies when each pattern is the right reach.
Permissions posture
None. PhotosPicker mediates — the system shows the picker, the app receives only the chosen item. NSPhotoLibraryUsageDescription is not required and not provided. The app cannot read the user's full photo library; it can only act on what the user explicitly picks.
Build + deployment
- App name: IntelligenceDemo.
- Platforms: iPhone primary. iPad inherits.
- Frameworks: SwiftUI, PhotosUI (PhotosPicker), Vision (VNRecognizeTextRequest), UIKit (the
UIImagebridge). - Privacy: No data leaves the device. No network. No analytics. The photo never leaves the OS-mediated picker handoff.
- Distribution: Demo / reference. GitHub clone-and-build is the primary path. App Store presence is the production evolution covered by Snap & ScanKeeper (Appendix U).
Relationship to Snap & ScanKeeper
Per the 2026-05-05 decision documented in project memory, IntelligenceDemo and Snap & ScanKeeper stay separate. The two apps demonstrate the same concept (turn an image into text / a saved artifact) at two different scales:
- IntelligenceDemo — chapter-teaching baseline. Two files. One screen. The smallest thing that works.
- Snap & ScanKeeper (Appendix U) — production evolution. VisionKit document camera (not Vision OCR on a Photos image), multi-page PDFs, custom Photos albums, share sheet, settings. Real product.
Reading them back-to-back is the case study: how a proof-of-concept grows into a shipped product. The chapter teaches on the demo; the source-tour follow-up walks the production version.
Known gotchas
VNRecognizeTextRequesthas two recognition levels..fastis faster but less accurate;.accurateis slower and better. The demo uses one or the other — pick deliberately based on whether you care about per-character accuracy or throughput.- PhotosPicker returns
Transferabledata. Decoding it toUIImagecan fail if the picked item isn't actually an image (some video formats, broken metadata). Theload(item:)method handles the optional unwrap. - The "the error IS the result" pattern doesn't generalize. It works here because there's a single output slot and the user expects text. In a multi-output app or an app with side effects, hide-the-error-in-the-result is worse UX than a proper error surface.
- Vision OCR is on-device. The image and the recognized text both stay on the user's device. No network round-trip, no privacy risk beyond what the user can already do with their own photos.
Sources
- Project source: github.com/fluhartyml/IntelligenceDemo (verified 2026-05-10).
- Build-Along chapter: Part VII Build-Along 08.
- Book 06 cross-reference:
PhotosPickeruser-mediated photo picker. - Book 12 cross-reference:
PhotosPickeras the framework-drives-the-sheet end of the sheet-presentation spectrum. - Book 14 cross-reference:
.textSelection(.enabled)for system-handled long-press / copy. - Book 18 cross-reference: "the error IS the result" inline-error pattern.
- Related production evolution: Appendix U (Snap & ScanKeeper).