AVCamBarcode: detecting barcodes and faces
At a glance
| Item |
Summary |
| Purpose |
Detect machine-readable codes and faces in a configurable region, then draw interactive overlays. |
| App architecture |
Storyboard-driven UIKit app centered on one CameraViewController that owns the capture graph and coordinates specialized views. |
| Main patterns |
View Controller/MVC-style coordination, AVFoundation delegate callback, weak selection delegate, serial session and metadata queues. |
| Project style |
Flat target with one main controller, a preview view, a reusable generic selection controller, and storyboards. |
Project structure
AVCamBarcode/
├── AppDelegate.swift
├── CameraViewController.swift
├── PreviewView.swift
├── ItemSelectionViewController.swift
├── Base.lproj/
│ ├── Main.storyboard
│ └── LaunchScreen.storyboard
└── Assets.xcassets/
Structure observations
- Most capture, authorization, configuration, overlay, and UI coordination logic is colocated in
CameraViewController.
PreviewView owns preview-layer and resizable-region rendering behavior.
ItemSelectionViewController<Item> is the only extracted reusable UI component and communicates completion through a protocol.
Overall architecture
flowchart LR
Storyboard["Storyboard"] --> Controller["CameraViewController"]
Controller --> Session["AVCaptureSession"]
Session --> Metadata["AVCaptureMetadataOutput"]
Metadata -->|delegate callback| Controller
Controller --> Overlay["MetadataObjectLayer objects"]
Overlay --> Preview["PreviewView / AVCaptureVideoPreviewLayer"]
Selector["ItemSelectionViewController"] -->|delegate selection| Controller
Reference code
AVCamBarcode/CameraViewController.swift:257 — metadata-output wiring
if session.canAddOutput(metadataOutput) {
session.addOutput(metadataOutput)
metadataOutput.setMetadataObjectsDelegate(self, queue: metadataObjectsQueue)
metadataOutput.metadataObjectTypes = metadataOutput.availableMetadataObjectTypes
}
Interpretation
The controller is both presentation coordinator and capture coordinator. Metadata arrives on a dedicated queue, is transformed into Core Animation overlays on the main queue, and is displayed over the preview layer. This is a compact UIKit sample rather than a separated service/view-model architecture.
Ownership and state
classDiagram
CameraViewController *-- AVCaptureSession : creates
CameraViewController *-- AVCaptureMetadataOutput : creates
CameraViewController *-- MetadataObjectLayer : creates and retains
CameraViewController o-- PreviewView : storyboard outlet
ItemSelectionViewController o-- ItemSelectionViewControllerDelegate : weak
PreviewView *-- CAShapeLayer : region controls
Ownership evidence
AVCamBarcode/CameraViewController.swift:173 — capture and UI references
private let session = AVCaptureSession()
private let sessionQueue = DispatchQueue(label: "session queue")
@IBOutlet private var previewView: PreviewView!
private let metadataOutput = AVCaptureMetadataOutput()
| Owner |
Object or state |
Relationship |
Mutation authority |
CameraViewController |
Session, metadata output, queues, overlays |
Creates and retains capture objects; receives storyboard view |
Controller methods, with session work dispatched to sessionQueue. |
PreviewView |
Preview backing layer and region-of-interest shape/control layers |
Owns visual region state |
PreviewView; external callers propose a region through one method. |
ItemSelectionViewController |
Selected items |
Owns selection state while presented |
Selection controller; final value returns through delegate. |
ItemSelectionViewController |
Delegate |
Weak shared reference |
The presenting controller implements the callback; selector does not own it. |
Class and protocol design
| Type |
Responsibility |
Depends on |
CameraViewController |
Configure capture, handle metadata, coordinate UI and overlays |
AVFoundation, PreviewView, selection controller, Safari services |
PreviewView |
Host preview layer and provide draggable/resizable detection region |
UIKit, AVFoundation, Core Animation |
ItemSelectionViewController<Item> |
Present single/multiple choice for any equatable raw-representable item |
UIKit, delegate protocol |
ItemSelectionViewControllerDelegate |
Return generic selected values to the presenter |
Selection controller |
Access control
| Symbol |
Access |
Verified effect |
Likely rationale |
| Session, outputs, queues, outlets, and overlay helpers |
private |
Capture graph and UI wiring are usable only by CameraViewController |
Prevents unrelated files from mutating order-sensitive controller state. |
PreviewView.regionOfInterest |
private(set) |
Controller/KVO can read it, but only PreviewView changes it |
Enforces clamping and redraw through setRegionOfInterestWithProposedRegionOfInterest. |
| Selection delegate |
weak, implicit internal |
Avoids a retain cycle while permitting the presenter callback |
Standard UIKit delegate ownership. |
| Main classes/protocol |
implicit internal |
Visible inside the app module, not exported |
The sample is an application target. |
Reference code
AVCamBarcode/PreviewView.swift:137 — constrained region mutation
@objc private(set) dynamic var regionOfInterest = CGRect.null
func setRegionOfInterestWithProposedRegionOfInterest(
_ proposedRegionOfInterest: CGRect
) {
// Clamp, assign, and redraw.
}
No public, open, or fileprivate declaration appears in the Swift source.
Logic ownership and placement
| Logic |
Owning type or file |
Placement rationale |
| Authorization/session lifecycle |
CameraViewController |
Coupled to view appearance and controller alerts. |
| Session mutation |
Controller private methods on sessionQueue |
AVFoundation session operations are serialized off-main. |
| Metadata-to-overlay transformation |
CameraViewController |
Requires both metadata output and preview-layer coordinates. |
| Region gesture/clamping/drawing |
PreviewView |
Geometry and layers remain inside the view that owns them. |
| Metadata-type/preset selection |
ItemSelectionViewController plus controller delegate |
Generic UI is separate; domain application stays with the camera controller. |
Design patterns
| Pattern |
Source evidence |
Purpose or tradeoff |
| UIKit View Controller/MVC-style coordinator |
AVCamBarcode/CameraViewController.swift:12 |
Centralizes a small sample, at the cost of a large multipurpose controller. |
| Delegate |
AVCamBarcode/CameraViewController.swift:12 and metadataOutput(_:didOutput:from:) at line 792 |
Receives asynchronous AVFoundation metadata. |
| Weak app delegate protocol |
AVCamBarcode/ItemSelectionViewController.swift:10 and line 16 |
Reuses selection UI without owning or knowing the presenting controller. |
| Thread confinement |
AVCamBarcode/CameraViewController.swift:177 and session-queue calls |
Keeps blocking/session mutation away from the main queue. |
| Backpressure/drop-latest behavior |
AVCamBarcode/CameraViewController.swift:792 and nonblocking semaphore wait |
Avoids accumulating stale overlay work. |
Main application flow
sequenceDiagram
participant Output as Metadata output
participant Controller as CameraViewController
participant Main as Main queue
participant Preview as Preview layer
Output->>Controller: didOutput metadataObjects
Controller->>Controller: nonblocking semaphore wait
Controller->>Main: transform objects and build layers
Main->>Preview: replace overlay layers
Main->>Controller: signal semaphore
Reference code
AVCamBarcode/CameraViewController.swift:792 — overlay callback
func metadataOutput(_ output: AVCaptureMetadataOutput,
didOutput metadataObjects: [AVMetadataObject],
from connection: AVCaptureConnection) {
if metadataObjectsOverlayLayersDrawingSemaphore.wait(timeout: .now()) == .success {
DispatchQueue.main.async {
// Replace overlays, then signal.
}
}
}
Naming conventions
- Types: UIKit role suffixes (
ViewController, View) and framework-aligned MetadataObjectLayer.
- Protocol: collaborator role with
Delegate suffix.
- Methods: lifecycle/configuration commands (
configureSession, changeCamera) and delegate signatures dictated by AVFoundation/UIKit.
- State:
is... for Boolean status; ...Queue, ...Output, and ...Layer suffixes expose object roles.
- Files: one primary UIKit type per Swift file; storyboard resources are grouped in
Base.lproj.
Architecture takeaways
- The source favors a conventional, controller-heavy UIKit sample over MVVM or service extraction.
- Separate serial queues protect capture configuration and metadata delivery; Core Animation changes return to the main queue.
- The preview view owns interactive geometry, while the controller owns detection semantics and overlay creation.
private(set) makes a view invariant explicit: outside code can observe the region but cannot bypass validation.
- The generic selection controller is protocol-oriented at one narrow reuse point rather than across the whole app.
Source map
| Source file |
Relevant symbols |
AVCamBarcode/CameraViewController.swift |
CameraViewController, MetadataObjectLayer, capture and overlay flow |
AVCamBarcode/PreviewView.swift |
PreviewView, preview layer, region-of-interest state |
AVCamBarcode/ItemSelectionViewController.swift |
Generic selection controller and delegate protocol |
AVCamBarcode/AppDelegate.swift |
UIKit application lifecycle entry |