Use when encountering "Unable to simultaneously satisfy constraints" errors, constraint conflicts, ambiguous layout warnings, or views positioned incorrectly - systematic debugging workflow for Auto Layout issues in iOS
Use when encountering "Unable to simultaneously satisfy constraints" errors, constraint conflicts, ambiguous layout warnings, or views positioned incorrectly - systematic debugging workflow for Auto Layout issues in iOS
license
MIT
metadata
{"version":"1.0.0"}
Auto Layout Debugging
When to Use This Skill
Use when:
Seeing "Unable to simultaneously satisfy constraints" errors in console
Views positioned incorrectly or not appearing
Constraint warnings during app launch or navigation
Ambiguous layout errors
Views appearing at unexpected sizes
Debug View Hierarchy shows misaligned views
Storyboard/XIB constraints behaving differently at runtime
Overview
Core Principle: Auto Layout constraint errors follow predictable patterns. Systematic debugging with proper tools identifies issues in minutes instead of hours.
Time Savings: Typical constraint debugging without this workflow: 30-60 minutes. With systematic approach: 5-10 minutes.
Quick Decision Tree
Constraint error in console?
├─ Can't identify which views?
│ └─ Use Symbolic Breakpoint + Memory Address Identification
├─ Constraint conflicts shown?
│ └─ Use Constraint Priority Resolution
├─ Ambiguous layout (multiple solutions)?
│ └─ Use _autolayoutTrace to find missing constraints
└─ Views positioned incorrectly but no errors?
└─ Use Debug View Hierarchy + Show Constraints
Understanding Constraint Error Messages
Anatomy of Error Message
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list you don't need.
(
"<NSLayoutConstraint:0x7f8b9c6... 'UIView-Encapsulated-Layout-Width' ... (active)>",
"<NSLayoutConstraint:0x7f8b9c5... UILabel:0x7f8b9c4... .width == 300 (active)>",
"<NSLayoutConstraint:0x7f8b9c3... UILabel:0x7f8b9c4... .leading == ... + 20 (active)>",
"<NSLayoutConstraint:0x7f8b9c2... ... .trailing == UILabel:0x7f8b9c4... .trailing + 20 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7f8b9c5... UILabel:0x7f8b9c4... .width == 300 (active)>
Key Components:
Memory addresses — 0x7f8b9c4... identifies views and constraints
Visual Format — Human-readable constraint description
(active) status — Constraint is currently enforced
Recovery action — Which constraint system will break (usually lowest priority)
System-Generated Constraints
UIView-Encapsulated-Layout-Width/Height:
Created by UIKit for cells, system views
Often source of conflicts
Usually correct; your constraints are the problem
Autoresizing Mask Constraints:
Format: h=--& or v=&--
- = fixed dimension
& = flexible dimension
Example: h=--& = fixed left margin and width, flexible right margin
Debugging Workflow
Step 1: Set Up Symbolic Breakpoint (One-Time Setup)
Purpose: Break when constraint conflict occurs, before system breaks constraint.
Setup:
Open Breakpoint Navigator (⌘+7 or ⌘+8)
Click + → "Symbolic Breakpoint"
Symbol: UIViewAlertForUnsatisfiableConstraints
(Optional) Add Action → "Sound" → select sound
(Optional) Check "Automatically continue after evaluating actions"
Why this works: Pauses execution at exact moment of constraint conflict, giving you debugger access to all views and constraints.
Step 2: Identify Views from Memory Addresses
When breakpoint hits, console shows memory addresses like UILabel:0x7f8b9c4...
Technique 1: Use %rbx Register (When Breakpoint Hits)
# Print all involved views and constraints
po $arg1
# Or on older Xcode versions
po $rbx
Output: NSArray containing all conflicting constraints and affected views.
Technique 2: Set View Background Color
# Set background color on suspected view
expr ((UIView *)0x7f8b9c4...).backgroundColor = [UIColor redColor]
# Continue execution to see which view turned red
Result: Visually identifies which view corresponds to memory address.
// Let width be calculated from leading + trailing
imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive =true
imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive =true// Width will be container width - 40
✅ CORRECT Option 2 (Use priorities):
let widthConstraint = imageView.widthAnchor.constraint(equalToConstant: 300)
widthConstraint.priority = .defaultHigh // 750 (can be broken if needed)
widthConstraint.isActive =true
imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive =true
imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive =true// Required constraints (1000) will break lower-priority width constraint if needed
Pattern 2: UIView-Encapsulated-Layout Conflicts
Symptom: Table cells or collection view cells conflicting with UIView-Encapsulated-Layout-Width.
Why it happens: System sets cell width based on table/collection view. Your constraints fight it.
❌ WRONG:
// In UITableViewCell
contentLabel.widthAnchor.constraint(equalToConstant: 320).isActive =true// Conflicts with system-determined cell width
✅ CORRECT:
// Use relative constraints, not fixed widths
contentLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16).isActive =true
contentLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16).isActive =true// Width adapts to cell width automatically
Pattern 3: Autoresizing Mask Conflicts
Symptom: Mixing Auto Layout with autoresizingMask or not setting translatesAutoresizingMaskIntoConstraints = false.
❌ WRONG:
let imageView =UIImageView()
view.addSubview(imageView)
// Forgot to disable autoresizing mask
imageView.widthAnchor.constraint(equalToConstant: 100).isActive =true// Conflicts with autoresizing mask constraints