Text is detected but characters are wrong (e.g., "C001" → "COOL")
Diagnostic
:
// Check all candidates, not just first
for
observation
in
results
{
let
candidates
=
observation
.
topCandidates
(
5
)
for
(
i
,
candidate
)
in
candidates
.
enumerated
(
)
{
print
(
"Candidate
(
i
)
'
(
candidate
.
string
)
' (
(
candidate
.
confidence
)
)
"
)
}
}
Common causes
:
Input Type
Problem
Fix
Serial numbers
Language correction "fixes" them
Disable
usesLanguageCorrection
Technical codes
Misread as words
Add to
customWords
Non-English
Wrong ML model
Set correct
recognitionLanguages
House numbers
Stylized → misread
Check all candidates, not just top
Fix for codes/serial numbers
:
let
request
=
VNRecognizeTextRequest
(
)
request
.
usesLanguageCorrection
=
false
// Don't "fix" codes
// Post-process with domain knowledge
func
correctSerialNumber
(
_
text
:
String
)
->
String
{
text
.
replacingOccurrences
(
of
:
"O"
,
with
:
"0"
)
.
replacingOccurrences
(
of
:
"l"
,
with
:
"1"
)
.
replacingOccurrences
(
of
:
"S"
,
with
:
"5"
)
}
Time to fix
30 min
Pattern 9c: Text Recognition Too Slow
Symptom
Text recognition takes >500ms, real-time camera drops frames
Diagnostic
:
let
start
=
CFAbsoluteTimeGetCurrent
(
)
try
handler
.
perform
(
[
request
]
)
let
elapsed
=
CFAbsoluteTimeGetCurrent
(
)
-
start
print
(
"Recognition took
(
elapsed
*
1000
)
ms"
)
print
(
"Recognition level:
(
request
.
recognitionLevel
==
.
fast
?
"fast"
:
"accurate"
)
"
)
print
(
"Language correction:
(
request
.
usesLanguageCorrection
)
"
)
Common causes & fixes
:
Cause
Fix
Speedup
Using
.accurate
for real-time
Switch to
.fast
3-5x
Language correction enabled
Disable for codes
20-30%
Full image processing
Use
regionOfInterest
2-4x
Processing every frame
Skip frames
50-70%
Fix for real-time
:
request
.
recognitionLevel
=
.
fast
request
.
usesLanguageCorrection
=
false
request
.
regionOfInterest
=
CGRect
(
x
:
0.1
,
y
:
0.3
,
width
:
0.8
,
height
:
0.4
)
// Skip frames
frameCount
+=
1
guard
frameCount
%
3
==
0
else
{
return
}
Time to fix
30 min
Pattern 10a: Barcode Not Detected (Symbology/Size)
Symptom
:
VNDetectBarcodesRequest
returns no results
Diagnostic
:
let
request
=
VNDetectBarcodesRequest
(
)
// Don't specify symbologies to detect all types
try
handler
.
perform
(
[
request
]
)
if
let
results
=
request
.
results
as
?
[
VNBarcodeObservation
]
{
print
(
"Found
(
results
.
count
)
barcodes"
)
for
barcode
in
results
{
print
(
"Type:
(
barcode
.
symbology
)
"
)
print
(
"Payload:
(
barcode
.
payloadStringValue
??
"nil"
)
"
)
print
(
"Bounds:
(
barcode
.
boundingBox
)
"
)
}
}
else
{
print
(
"❌ No barcodes detected"
)
}
Common causes
:
Cause
Symptom
Fix
Wrong symbology
Not detected
Don't filter, or add correct type
Barcode too small
Not detected
Move camera closer, crop image
Glare/reflection
Not detected
Change angle, improve lighting
Damaged barcode
Partial/no detection
Clean barcode, improve image
Using revision 1
Only one code
Use revision 2+ for multiple
Fix for small barcodes
:
// Crop to barcode region for better detection
let
croppedHandler
=
VNImageRequestHandler
(
cgImage
:
croppedImage
,
options
:
[
:
]
)
Time to fix
20 min
Pattern 10b: Wrong Barcode Payload
Symptom
Barcode detected but
payloadStringValue
is wrong or nil
Diagnostic
:
if
let
barcode
=
results
.
first
{
print
(
"String payload:
(
barcode
.
payloadStringValue
??
"nil"
)
"
)
print
(
"Raw payload:
(
barcode
.
payloadData
??
Data
(
)
)
"
)
print
(
"Symbology:
(
barcode
.
symbology
)
"
)
print
(
"Confidence: Implicit (always 1.0 for barcodes)"
)
}
Common causes
:
Cause
Fix
Binary barcode (not string)
Use
payloadData
instead
Damaged code
Re-scan or clean barcode
Wrong symbology assumed
Check actual
symbology
value
Time to fix
15 min
Pattern 11a: DataScanner Blank Screen
Symptom
:
DataScannerViewController
shows black/blank when presented
Diagnostic
:
// Check support first
print
(
"isSupported:
(
DataScannerViewController
.
isSupported
)
"
)
print
(
"isAvailable:
(
DataScannerViewController
.
isAvailable
)
"
)
// Check camera permission
let
status
=
AVCaptureDevice
.
authorizationStatus
(
for
:
.
video
)
print
(
"Camera access:
(
status
.
rawValue
)
"
)
Common causes
:
Symptom
Cause
Fix
isSupported = false
Device lacks camera/chip
Check before presenting
isAvailable = false
Parental controls or access denied
Request camera permission
Black screen
Camera in use by another app
Ensure exclusive access
Crash on present
Missing entitlements
Add camera usage description
Fix
:
guard
DataScannerViewController
.
isSupported
else
{
showError
(
"Scanning not supported on this device"
)
return
}
guard
DataScannerViewController
.
isAvailable
else
{
// Request camera access
AVCaptureDevice
.
requestAccess
(
for
:
.
video
)
{
granted
in
// Retry after access granted
}
return
}
Time to fix
15 min
Pattern 11b: DataScanner Items Not Detected
Symptom
DataScanner shows camera but doesn't recognize items
Diagnostic
:
// Check recognized data types
print
(
"Data types:
(
scanner
.
recognizedDataTypes
)
"
)
// Add delegate to see what's happening
func
dataScanner
(
_
scanner
:
DataScannerViewController
,
didAdd items
:
[
RecognizedItem
]
,
allItems
:
[
RecognizedItem
]
)
{
print
(
"Added
(
items
.
count
)
items, total:
(
allItems
.
count
)
"
)
for
item
in
items
{
switch
item
{
case
.
text
(
let
text
)
:
print
(
"Text:
(
text
.
transcript
)
"
)
case
.
barcode
(
let
barcode
)
:
print
(
"Barcode:
(
barcode
.
payloadStringValue
??
""
)
"
)
@unknown
default
:
break
}
}
}
Common causes
:
Cause
Fix
Wrong data types
Add correct
.barcode(symbologies:)
or
.text()
Text content type filter
Remove filter or use correct type
Camera too close/far
Adjust distance
Poor lighting
Improve lighting
Time to fix
20 min
Pattern 12a: Document Edges Not Detected
Symptom
:
VNDetectDocumentSegmentationRequest
returns no results
Diagnostic
:
let
request
=
VNDetectDocumentSegmentationRequest
(
)
try
handler
.
perform
(
[
request
]
)
if
let
observation
=
request
.
results
?
.
first
{
print
(
"Document found at:
(
observation
.
boundingBox
)
"
)
print
(
"Corners: TL=
(
observation
.
topLeft
)
, TR=
(
observation
.
topRight
)
"
)
}
else
{
print
(
"❌ No document detected"
)
}
Common causes
:
Cause
Fix
Low contrast
Use contrasting background
Non-rectangular
ML expects rectangular documents
Glare/reflection
Change lighting angle
Document fills frame
Need some background visible
Fix
Use VNDocumentCameraViewController for guided user experience with live feedback.
Time to fix
15 min
Pattern 12b: Perspective Correction Wrong
Symptom
Document extracted but distorted
Diagnostic
:
// Verify corner order
print
(
"TopLeft:
(
observation
.
topLeft
)
"
)
print
(
"TopRight:
(
observation
.
topRight
)
"
)
print
(
"BottomLeft:
(
observation
.
bottomLeft
)
"
)
print
(
"BottomRight:
(
observation
.
bottomRight
)
"
)
// Check if corners are in expected positions
// TopLeft should have larger Y than BottomLeft (Vision uses lower-left origin)
Common causes
:
Cause
Fix
Corner order wrong
Vision uses counterclockwise from top-left
Coordinate system
Convert normalized to pixel coordinates
Filter parameters wrong
Check CIPerspectiveCorrection parameters
Fix
:
// Scale normalized to image coordinates
func
scaled
(
_
point
:
CGPoint
,
to size
:
CGSize
)
->
CGPoint
{
CGPoint
(
x
:
point
.
x
*
size
.
width
,
y
:
point
.
y
*
size
.
height
)
}
Time to fix
20 min
Production Crisis Scenario
Situation
App Store review rejected for "app freezes when tapping analyze button"
Triage (5 min)
:
Confirm Vision running on main thread → Pattern 5a
Verify on older device (iPhone 12) → Freezes
Check profiling: 800ms on main thread
Fix (15 min)
:
@IBAction
func
analyzeTapped
(
_
sender
:
UIButton
)
{
showLoadingIndicator
(
)
DispatchQueue
.
global
(
qos
:
.
userInitiated
)
.
async
{
[
weak
self
]
in
let
request
=
VNGenerateForegroundInstanceMaskRequest
(
)
// ... perform request
DispatchQueue
.
main
.
async
{
self
?
.
hideLoadingIndicator
(
)
self
?
.
updateUI
(
with
:
results
)
}
}
}
Communicate to PM
:
"App Store rejection due to Vision processing on main thread. Fixed by moving to background queue (industry standard). Testing on iPhone 12 confirms fix. Safe to resubmit."