Auto Layout and Rendering
Intrinsic content size and constraint priorities, debugging constraint conflicts, self-sizing cells, and what wrecks scroll rendering (offscreen passes).
9 questions
JuniorTheoryVery commonWhat is intrinsic content size, which views have one, and what happens to a view with none?
What is intrinsic content size, which views have one, and what happens to a view with none?
Intrinsic content size is the size a view derives from its own content — a UILabel from its text, a UIButton from its title. A plain UIView has none, so without constraints sizing it fully, its size stays ambiguous.
Common mistakes
- ✗Assuming every view including a plain
UIViewreports an intrinsic size - ✗Thinking a view with no intrinsic size sizes itself from its subviews automatically
- ✗Confusing intrinsic content size with the frame given by the parent
Follow-up questions
- →Which value does a view return when it has no intrinsic dimension on an axis?
- →How do content hugging and compression resistance act on the intrinsic size?
SeniorDesignVery commonDesign a UIKit screen that adapts across iPhone, iPad, and iPad Split View without shipping a separate layout per device. It reflows a primary content area and a secondary detail panel — side by side when there is width, stacked when there is not. Constraints — no hardcoded device checks or magic point values, the same view-controller code serves every size, and text and controls respect Dynamic Type and the safe area. Explain how you drive the arrangement from UIKit's adaptive-layout API (size classes and trait collections) plus layout guides, how you switch between the side-by-side and stacked forms, and what you deliberately avoid hardcoding.
Design a UIKit screen that adapts across iPhone, iPad, and iPad Split View without shipping a separate layout per device. It reflows a primary content area and a secondary detail panel — side by side when there is width, stacked when there is not. Constraints — no hardcoded device checks or magic point values, the same view-controller code serves every size, and text and controls respect Dynamic Type and the safe area. Explain how you drive the arrangement from UIKit's adaptive-layout API (size classes and trait collections) plus layout guides, how you switch between the side-by-side and stacked forms, and what you deliberately avoid hardcoding.
Drive the layout from the trait collection's horizontal size class, not the device model — regular width places content and detail side by side, compact stacks them. Switch sets in traitCollectionDidChange, activating one constraint set and deactivating the other. Pin to safeAreaLayoutGuide and readableContentGuide, let Dynamic Type size the text, and hardcode no device checks.
Common mistakes
- ✗Branching on device idiom instead of the horizontal size class
- ✗Ignoring Split View, where an iPad app runs in a compact width
- ✗Pinning to raw bounds instead of the safe-area and readable-content guides
Follow-up questions
- →How do you animate the transition when the size class changes mid-session?
- →Why does Split View make device-idiom branching unreliable on iPad?
JuniorTheoryCommonWhat does an Auto Layout constraint express, and what makes a layout ambiguous?
What does an Auto Layout constraint express, and what makes a layout ambiguous?
A constraint is a linear equation attr1 = m × attr2 + c with a priority; the engine solves the whole system for each view's frame. A layout is ambiguous when under-constrained — too few constraints to fix a unique size and position.
Common mistakes
- ✗Confusing ambiguous (under-constrained) with unsatisfiable (over-constrained)
- ✗Thinking a constraint stores an absolute frame instead of a relation
- ✗Forgetting a constraint carries a priority, not just an equality
Follow-up questions
- →How does a constraint's priority change which one the engine breaks first?
- →How do you list the ambiguously-laid-out views at runtime?
MiddleDebuggingCommonReading an 'Unable to simultaneously satisfy constraints' log
Reading an 'Unable to simultaneously satisfy constraints' log
The log lists every conflicting constraint and names the one it broke. Give each an .identifier to map the addresses to code, then find the over-constrained axis — a fixed 200-pt width fighting the leading and trailing pins. Remove one or lower its priority.
Common mistakes
- ✗Ignoring the warning because the app still renders something
- ✗Deleting the first listed constraint without finding the real conflict
- ✗Leaving constraints unnamed so the addresses can't be traced to code
Follow-up questions
- →How does a symbolic breakpoint on the layout assertion help you catch it live?
- →Why does lowering a priority resolve a conflict better than deleting a constraint?
MiddleTheoryCommonTwo labels in a row: which truncates, and how do hugging and compression resistance decide it?
Two labels in a row: which truncates, and how do hugging and compression resistance decide it?
Compression resistance is how hard a view fights shrinking below its intrinsic size; content hugging is how hard it fights growing beyond it. When two labels can't both fit a row, the one with lower compression-resistance priority truncates — raise it on the label that must stay whole.
Common mistakes
- ✗Swapping the roles of hugging and compression resistance
- ✗Thinking insertion order, not priority, decides which label clips
- ✗Believing character count rather than priority drives truncation
Follow-up questions
- →What does content hugging decide when the row has extra space instead of too little?
- →Why keep both labels' priorities distinct rather than equal?
JuniorPerformanceOccasionalWhy does a deeply nested Auto Layout hierarchy in a cell drop frames, and when do you go manual?
Why does a deeply nested Auto Layout hierarchy in a cell drop frames, and when do you go manual?
The solver's cost grows worse than linearly with constraint count, and a deep cell hierarchy re-solves the system each layout pass on the main thread. Fast scroll blows the frame budget. Flatten the hierarchy or go manual with layoutSubviews.
Common mistakes
- ✗Assuming solver cost is linear rather than superlinear in constraint count
- ✗Believing layout runs off the main thread and never affects frames
- ✗Reaching for lower image quality before simplifying the constraint graph
Follow-up questions
- →How does cell reuse interact with the per-pass re-solve cost?
- →What signals in Instruments point at layout rather than drawing as the cause?
JuniorPerformanceOccasionalWhat triggers an offscreen rendering pass while scrolling, and how do you avoid it?
What triggers an offscreen rendering pass while scrolling, and how do you avoid it?
Offscreen rendering forces a buffer pass before compositing, costly mid-scroll. cornerRadius with masksToBounds, a shadow with no shadowPath, and masks or blurs trigger it. Set shadowPath, pre-round images, or rasterize static layers.
Common mistakes
- ✗Thinking offscreen rendering means a view being off-screen
- ✗Leaving shadows without a
shadowPathand paying an alpha-derived pass - ✗Assuming opacity alone removes corner-radius and shadow passes
Follow-up questions
- →Why does an explicit
shadowPathremove the offscreen pass a shadow would cost? - →When is
shouldRasterizea net win rather than a cost?
JuniorPerformanceOccasionalWhat does estimatedRowHeight do, and why does the scroll indicator jump while you scroll?
What does estimatedRowHeight do, and why does the scroll indicator jump while you scroll?
estimatedRowHeight gives the table an approximate height so it sizes scroll content without measuring every cell first; real heights compute lazily as cells appear. The indicator jumps because each corrected estimate updates content height mid-scroll.
Common mistakes
- ✗Thinking the estimate is the final height rather than a placeholder
- ✗Assuming all real heights are computed up front instead of lazily
- ✗Blaming the jump on a bug rather than content-height correction
Follow-up questions
- →What happens to scroll behaviour if the estimate is far off from real heights?
- →Why does a good estimate reduce the visible jumping?
MiddleDebuggingOccasionalA self-sizing cell renders at the wrong height on first layout
A self-sizing cell renders at the wrong height on first layout
title is pinned top, leading, and trailing but never to contentView.bottomAnchor, so the vertical chain never reaches the bottom and the cell height is ambiguous, staying at the estimate. Add the missing bottom constraint so the height flows from content.
Common mistakes
- ✗Leaving a gap in the top-to-bottom constraint chain of the contentView
- ✗Treating the estimate as the final height rather than a placeholder
- ✗Blaming reload timing instead of the ambiguous vertical constraints
Follow-up questions
- →Why must the chain reach
contentView.bottomAnchorspecifically, not the cell's? - →How would a multiline label's
numberOfLines = 0interact with this chain?