Auto Layout: Constraints, Anchors, and Resolving Ambiguity

Understand how Auto Layout describes a view's geometry declaratively through constraints and anchors, how priorities, intrinsic content size, hugging, and compression resistance interact to resolve a layout, and how to recognize and debug ambiguous or conflicting constraint sets.

Every view on screen needs a frame — an origin and a size — before it can be drawn, and for a long time Objective-C developers computed those frames by hand: adding up widths, subtracting margins, and manually repositioning every sibling view whenever one of them changed size. Auto Layout replaces that manual arithmetic with a declarative system: instead of telling a view where it is, you describe the *relationships* that must hold between views — 'this button's leading edge sits 16 points from its superview's leading edge,' 'this label's top sits 8 points below that image view's bottom' — and a constraint-solving engine works out every view's actual frame from the full set of relationships you've described. This lesson walks through that system from the ground up: how constraints and the modern anchor API express those relationships, how priorities let you express soft preferences rather than hard rules, how a view's intrinsic content size feeds into the solver, how hugging and compression resistance resolve competition between views that both want to control their own size, and — because a real layout eventually goes wrong — how to read the console warnings Auto Layout gives you when a layout is ambiguous or over-constrained.

Constraints: Describing Relationships Instead of Frames

A constraint is a single linear equation relating one geometric attribute of one view to another geometric attribute of another view (or a constant), roughly of the form item1.attribute1 = multiplier × item2.attribute2 + constant. 'This view's width equals its superview's width times 1.0, minus 32' is a constraint; so is 'this label's top equals that image view's bottom plus 8.' Auto Layout's job, at layout time, is to take the entire collection of constraints active on a view hierarchy and solve them simultaneously — the same way you'd solve a system of linear equations in algebra — to arrive at a single frame for every view that satisfies every constraint at once.

This is a genuine shift in how you think about layout. With manual frame-setting, you write imperative code: compute a value, assign it to view.frame, and if anything else needs to change as a result, you write more code to update it. With Auto Layout, you state facts about the relationships that must hold, once, and the system keeps re-deriving frames from those facts every time something changes — the screen rotates, dynamic type changes a label's size, a view is hidden, or content is added. You do not re-run layout code yourself in most cases; you add or remove or update constraints, and the solver figures out the geometric consequences.

Constraints can be created in three broad ways: dragging them out in Interface Builder (which is outside the scope of a code-focused course but produces the exact same underlying NSLayoutConstraint objects), using the older factory method +[NSLayoutConstraint constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:], or — the modern, and by far most readable, approach — the anchor-based API covered in the next section. Whichever way you create them, constraints are ordinary objects: you add them to a view with [view addConstraint:] (or, more commonly, activate them with constraint.active = YES), and you can remove or deactivate them later to change the layout.

One easy-to-miss but important rule is where a constraint should live: a constraint relating two sibling views, or a view to its superview, should be added to (or activated in the context of) their nearest common ancestor — typically the superview shared by both views it relates. A constraint added to the wrong view in the hierarchy either has no effect or produces a runtime exception, because Auto Layout can only resolve a relationship between views that share an ancestor it can actually lay out.

Anchors: The Modern, Type-Safe Way to Build Constraints

NSLayoutAnchor and its subclasses (NSLayoutXAxisAnchor, NSLayoutYAxisAnchor, NSLayoutDimension) give every view a set of properties representing its edges, its center lines, and its width and height: view.leadingAnchor, view.trailingAnchor, view.topAnchor, view.bottomAnchor, view.centerXAnchor, view.centerYAnchor, view.widthAnchor, and view.heightAnchor. Each anchor exposes methods like constraintEqualToAnchor:constant:, constraintGreaterThanOrEqualToAnchor:constant:, and constraintEqualToConstant: that return a fully configured, ready-to-activate NSLayoutConstraint — and because the anchor's type restricts which other anchors it can be paired with (an NSLayoutXAxisAnchor can only be related to another NSLayoutXAxisAnchor, never to a Y anchor), the compiler catches a whole class of nonsensical constraints — relating a leading edge to a top edge, for instance — that the older, purely string/enum-based API would only catch at runtime.

A typical block of anchor-based setup pins a subview's edges to its superview with a small cluster of constraint statements, each created from an anchor and immediately activated: [view.leadingAnchor constraintEqualToAnchor:superview.leadingAnchor constant:16].active = YES;, and similarly for the trailing, top, and bottom anchors. Because writing .active = YES on every line gets repetitive, NSLayoutConstraint also provides the class method +activateConstraints:, which takes an array of constraints and activates all of them in a single call — this is both more concise and measurably faster than activating constraints one at a time, since it lets Auto Layout batch its internal bookkeeping.

Before any of this works, you must disable the legacy autoresizing-mask-to-constraints translation on every view you intend to constrain by hand, by setting view.translatesAutoresizingMaskIntoConstraints = NO. Every UIView created in code defaults this property to YES, which tells Auto Layout to synthesize constraints from the view's frame and autoresizing mask automatically — convenient for views you genuinely want to size manually, but it silently fights with any constraints you add yourself, and forgetting to turn it off is one of the most common sources of a mysteriously broken layout for anyone new to Auto Layout.

Anchors compose naturally with layout guides too — view.safeAreaLayoutGuide.topAnchor pins a view below the status bar and notch/dynamic-island area rather than under it, and view.layoutMarginsGuide gives you a view's standard content margins as anchors, so you can pin to 'the margin' rather than hard-coding a numeric constant that duplicates the system's own spacing conventions.

Priorities: Preferences, Not Just Rules

Every constraint carries a priority, an integer from 1 to 1000, stored on the constraint's priority property as a UILayoutPriority value. A priority of 1000 (UILayoutPriorityRequired) means the constraint is mandatory — the solver treats it as a hard rule that must be satisfied, and if it's impossible to satisfy alongside other required constraints, that's a conflict (covered below). Any priority below 1000 is a preference: the solver will satisfy it if it can, but it is explicitly allowed to violate a lower-priority constraint rather than leave a higher-priority one, or a required one, unsatisfied.

This is what makes it possible to express 'prefer X, but allow Y under pressure' declaratively. A classic example is a view you'd like to be exactly 200 points wide, but which must never grow wider than its superview: you add a required (1000) constraint that the width be less than or equal to the superview's width, and a lower-priority (say 750) constraint that the width equal exactly 200. When there's room, both are satisfiable and the view is 200 points wide. When the superview is narrower than 200, the 1000-priority upper bound wins and the 750-priority exact-width constraint is broken — the view shrinks to fit, rather than the layout becoming unsatisfiable.

Two named constants, UILayoutPriorityDefaultHigh (750) and UILayoutPriorityDefaultLow (250), are the standard priorities the system itself uses for hugging and compression resistance (the next two sections), and they're a reasonable pair of values to build your own soft preferences around — high enough to usually win against the system defaults, low enough to still lose to anything genuinely required. You set a priority either on the constraint object directly (constraint.priority = 750;) before activating it, or, for anchor-created constraints, by assigning to .priority on the returned constraint before setting .active = YES.

Intrinsic Content Size: A View's Natural Size

Many views know their own preferred size just from their content, without any explicit width or height constraint from you. A UILabel sized to fit a single line of text at a given font has a natural width and height determined entirely by that text and font; a UIButton has a natural size based on its title and content insets; a UIImageView with an image set (and no explicit override) reports the image's own pixel dimensions. This natural size is the view's intrinsic content size, exposed through the method -intrinsicContentSize, which returns a CGSize (or UIViewNoIntrinsicMetric for a dimension the view has no opinion about — a plain UIView with no content, for instance, returns UIViewNoIntrinsicMetric for both dimensions).

Auto Layout treats a non-empty intrinsic content size as if the view had two additional constraints applied automatically — one pinning its width to the intrinsic width, one pinning its height to the intrinsic height — at the default content-hugging and compression-resistance priorities described next, rather than at required priority. This is precisely why you routinely add position constraints (pin the label's leading and top edges) to a UILabel and never bother adding explicit width or height constraints at all: the label's intrinsic content size supplies the size half of the equation on its own, and you only need to say where it goes.

You can override -intrinsicContentSize in a custom UIView subclass to give it the same automatic sizing behavior — a custom view that draws a fixed-size icon, for instance, can report that icon's size from -intrinsicContentSize and other views can then position relative to it exactly as they would around a label, without you writing an explicit width or height constraint anywhere for it. Whenever a change to a view's content would change what -intrinsicContentSize returns — new text in a label, a different image in an image view — you must call -invalidateIntrinsicContentSize so Auto Layout knows to re-query it and re-solve the layout; the system does this for you automatically inside UILabel and UIImageView, but a custom subclass overriding -intrinsicContentSize is responsible for calling it itself.

Content Hugging: Resisting Growth Beyond the Intrinsic Size

Content hugging priority controls how strongly a view resists being stretched larger than its intrinsic content size when there's extra space to distribute. Picture a single UILabel pinned to its superview's leading and top edges with no trailing constraint at all except through some other layout arrangement that leaves slack space — should that label grow past its intrinsic width to fill the extra space, or stay exactly as wide as its text needs? The content hugging priority answers that question: a higher hugging priority means the view fights harder to stay at its intrinsic size rather than stretching, while a lower hugging priority means the view is more willing to grow and absorb the extra space.

You read and set this priority per-axis with -contentHuggingPriorityForAxis: and -setContentHuggingPriority:forAxis:, passing UILayoutConstraintAxisHorizontal or UILayoutConstraintAxisVertical. The system default for most views is UILayoutPriorityDefaultLow (250) on both axes, which is why, in a row of several views where only one is meant to stretch to fill available space, you typically lower the hugging priority of that one view even further (or raise the others') so the solver has an unambiguous preference about which view absorbs the slack.

It helps to say plainly what 'hugging' means as a word: the view 'hugs' its own content tightly, resisting being pulled wider or taller than that content needs. A high hugging priority is a clingy view that refuses to stretch; a low hugging priority is a relaxed view that's happy to stretch and fill whatever space is offered to it.

Compression Resistance: Resisting Shrinkage Below the Intrinsic Size

Compression resistance priority is hugging's mirror image: it controls how strongly a view resists being squeezed smaller than its intrinsic content size when there isn't enough room for every view to be at its natural size simultaneously. Where hugging is about growth, compression resistance is about shrinkage — and the two are genuinely independent settings, each with its own priority per axis, because a view's willingness to grow and its willingness to shrink are two different design decisions that don't have to move together.

The canonical example that makes the contrast concrete is two labels side by side in a single row that's too narrow to show both at their full intrinsic width — say a 'title' label and a 'detail' label, pinned leading-to-trailing with a fixed gap, inside a cell that's narrower than their combined natural widths. Something has to give: one of the two labels has to shrink below its intrinsic width, which for text means truncation (an ellipsis) unless it's also allowed to wrap. Which one shrinks is entirely determined by which one has the *lower* compression resistance priority — the label with lower resistance loses the fight and gets compressed (and truncates), while the label with higher resistance holds its intrinsic width.

In the common title/detail pattern, you typically want the detail label (often a secondary, less critical piece of text, or one more likely to be long) to truncate before the title does, so you lower the detail label's horizontal compression resistance priority below the title label's — for example leaving the title at the system default UILayoutPriorityDefaultHigh (750) and dropping the detail label to something lower, or conversely raising the title's above the default. Whichever label ends up with the lower priority on that axis is the one that will visually truncate first as the available width shrinks.

Read and set compression resistance with -contentCompressionResistancePriorityForAxis: and -setContentCompressionResistancePriority:forAxis: — the same per-axis pattern as hugging, and the same default value (UILayoutPriorityDefaultHigh, 750, which is notably *higher* than hugging's default 250 — the system leans toward views keeping their full size and shrinking reluctantly, but growing to fill space fairly readily, unless you tell it otherwise).

Ambiguity: When the Solver Has No Unique Answer

A layout is ambiguous when the active set of constraints does not fully determine a unique frame for every view — there is more than one arrangement of frames that satisfies every constraint equally well, and the system has to pick one arbitrarily. A view with no horizontal position constraint at all, for instance, is ambiguous on the X axis: nothing says where its leading edge should be, so any X position technically satisfies the (nonexistent) horizontal constraints, and Auto Layout will place it somewhere, but that placement is not something you specified or can rely on.

The dangerous part of ambiguity is that it does not always look broken. The solver still has to produce *some* frame, and depending on the exact constraint set, it often happens to pick the frame you actually wanted, purely by coincidence of its internal solving order — the layout looks correct on the screen you're testing on, in the orientation you're testing in, with the content you're testing with. It is still a bug: change the device, the orientation, the dynamic type size, or the exact content, and the same underlying ambiguity can resolve to a visibly different, wrong frame, because nothing was ever pinning it to the frame you happened to see before. 'It looks fine right now' is not evidence that a layout is unambiguous.

You can query ambiguity directly with -hasAmbiguousLayout on a UIView, and force Auto Layout to deliberately jump between its valid candidate frames — so you can see exactly how much wiggle room the ambiguity allows — by calling -[UIWindow exerciseAmbiguityInLayoutRecursively] or the per-view -exerciseAmbiguityInLayout while debugging in the simulator; each call jitters the ambiguous views to a different, equally-valid frame, so a view that visibly jumps around confirms exactly which view and which axis is underconstrained.

Conflicts: When Required Constraints Cannot All Hold

A conflict is the opposite problem from ambiguity: instead of too few constraints, there are too many, and some subset of the required (priority 1000) constraints active at once is mutually unsatisfiable — there is no frame, for any view, that satisfies all of them simultaneously. A classic minimal example is pinning a view's width to exactly 100 with one required constraint and to exactly 200 with another required constraint on the same view — both cannot be true at once, so the system has a genuine contradiction on its hands.

When this happens at runtime, Auto Layout does not crash your app. It logs a detailed warning to the console — 'Unable to simultaneously satisfy constraints,' followed by a list of the specific conflicting NSLayoutConstraint objects — and then it *breaks* one of them: specifically, it picks the lowest-priority constraint among the conflicting set (if several are tied for lowest priority, the choice among those is effectively arbitrary) and deactivates just enough of them to make the remainder satisfiable, so layout can proceed and your app keeps running, just with a wrong (but at least defined) result.

This is exactly the mechanism priorities exist to control intentionally, as covered earlier: give the constraint you're willing to sacrifice a lower priority than 1000 on purpose, and it's no longer a conflict at all — it's a controlled trade-off the solver resolves silently, with no console warning, because a sub-1000 constraint losing to a required one is expected behavior, not an error. A real conflict warning in your console almost always means two constraints that were both meant to be required actually contradict each other, and the fix is to make one of them lower priority on purpose, or to remove/adjust one so they no longer contradict.

Debugging Constraints: Reading Warnings and Isolating Problems

The console warning Auto Layout logs for a conflict is dense but genuinely useful once you know how to read it: it lists each NSLayoutConstraint object involved in the conflicting set, printed with the two views and attributes it relates, its constant, and its priority, followed by a line naming exactly which one the system chose to break. Reading through that list to identify the constraint you actually intended to be a soft preference — and then explicitly lowering its priority, rather than leaving it at the required default and hoping the automatic break-the-lowest-priority-one behavior happens to pick correctly — turns a mysterious runtime warning into a one-line fix.

Xcode's view debugger (accessible while paused on a breakpoint, or via the 'Debug View Hierarchy' button) lets you inspect the live constraints active on any view in a running app, including their priorities and constants, and lets you select a problem view directly in a 3D exploded view of the hierarchy rather than guessing from console output alone which view in a complex screen is the one at fault. For ambiguity specifically, combining -hasAmbiguousLayout checks in code with exerciseAmbiguityInLayoutRecursively while watching the view debugger is the most direct way to confirm both that a view is ambiguous and exactly which axis and which frame candidates are in play.

The general debugging discipline that heads off most of these problems before they even happen is building a layout up incrementally rather than writing forty constraints at once and running the app to see what breaks: add position constraints for one view, run it, confirm it's right; add the next view's constraints, run it again; and so on. When something does go wrong with a large, all-at-once constraint set, the fastest way to isolate it is often to comment out constraints in groups and reintroduce them one group at a time until the conflict or ambiguity warning reappears — at which point you know exactly which addition caused it, rather than staring at the full set trying to spot the contradiction by inspection.

Anchor-Based Constraint Creation and Activation

translatesAutoresizingMaskIntoConstraints = NO is required on every view you constrain by hand, or it fights your constraints. Anchor types prevent nonsensical pairings at compile time — an X-axis anchor cannot be related to a Y-axis anchor. +activateConstraints: activates a whole batch in one call, which is both clearer and faster than setting .active one line at a time.

view.translatesAutoresizingMaskIntoConstraints = NO;   // required before adding your own constraints

NSLayoutConstraint *leading =
    [view.leadingAnchor constraintEqualToAnchor:superview.leadingAnchor constant:16];
NSLayoutConstraint *top =
    [view.topAnchor constraintEqualToAnchor:superview.topAnchor constant:8];
NSLayoutConstraint *width =
    [view.widthAnchor constraintGreaterThanOrEqualToConstant:44];

leading.priority = UILayoutPriorityRequired;   // 1000, the default for a fresh constraint
width.priority = UILayoutPriorityDefaultHigh;  // 750, a soft preference

[NSLayoutConstraint activateConstraints:@[leading, top, width]];  // activate in one batch

Code Examples

This method pins card's leading and trailing edges 16 points in from its superview's edges, its top 12 points below the safe area (so it clears the status bar/notch rather than the raw superview edge), and gives it a fixed height of 120 via a dimension anchor rather than a relationship to another view. Every constraint is built from an anchor property and activated together in one activateConstraints: call, which is the idiomatic modern pattern for a block of related constraints.

[card.topAnchor constraintEqualToAnchor:superview.safeAreaLayoutGuide.topAnchor constant:12],

Setting the title label's compression resistance to UILayoutPriorityRequired (1000) means it can never be shrunk below its intrinsic width by any constraint below priority 1000; giving the detail label a low compression resistance instead means the detail label is the one that gives ground — and truncates — when the row is too narrow for both at full size. Dropping the detail label's hugging priority a notch below the system default additionally tells it to stretch and absorb any leftover slack space in the row, rather than staying tight to its own text width the way the title does. In practice you would typically also set numberOfLines and lineBreakMode on detailLabel so the visual truncation reads correctly once it's compressed below its intrinsic width.

This debug-only check runs after every layout pass and asks badgeView directly whether Auto Layout considers its own frame ambiguous. If it does, logging a targeted message is far faster to act on than scanning the whole console for a generic warning, and calling exerciseAmbiguityInLayoutRecursively on the window jitters every ambiguous view in the hierarchy to an alternate, equally valid frame — if badgeView visibly jumps to a different position when you trigger a layout pass again, that confirms exactly which axis is underconstrained.

Common mistake: Relying only on 'it looks right in the simulator' instead of checking hasAmbiguousLayout — an ambiguous layout can render correctly by coincidence and only break later, on a different device or with different content.

- (void)layoutCardView:(UIView *)card inSuperview:(UIView *)superview {
    card.translatesAutoresizingMaskIntoConstraints = NO;

    [NSLayoutConstraint activateConstraints:@[
        [card.leadingAnchor constraintEqualToAnchor:superview.leadingAnchor constant:16],
        [card.trailingAnchor constraintEqualToAnchor:superview.trailingAnchor constant:-16],
        [card.topAnchor constraintEqualToAnchor:superview.safeAreaLayoutGuide.topAnchor constant:12],
        [card.heightAnchor constraintEqualToConstant:120],
    ]];
}
- (void)configureRowWithTitle:(UILabel *)titleLabel detail:(UILabel *)detailLabel {
    // Title must never truncate before detail does.
    [titleLabel setContentCompressionResistancePriority:UILayoutPriorityRequired
                                                  forAxis:UILayoutConstraintAxisHorizontal];
    [detailLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
                                                   forAxis:UILayoutConstraintAxisHorizontal];

    // Detail should stretch to fill leftover space; title should stay tight to its text.
    [detailLabel setContentHuggingPriority:UILayoutPriorityDefaultLow - 1
                                    forAxis:UILayoutConstraintAxisHorizontal];
}
- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

#if DEBUG
    if ([self.badgeView hasAmbiguousLayout]) {
        NSLog(@"badgeView layout is ambiguous — missing a horizontal position constraint?");
        [self.view.window exerciseAmbiguityInLayoutRecursively];
    }
#endif
}

Auto Layout in Real Apps

Virtually every non-trivial iOS interface built with UIKit relies on Auto Layout to adapt across the enormous range of screen sizes, orientations, and dynamic-type settings a single app must support — from a compact iPhone in portrait to a large iPad in split-view multitasking. Table and collection view cells (the next lesson) lean on intrinsic content size and hugging/compression resistance constantly, since a cell's height is very often derived entirely from its label's intrinsic size rather than a hard-coded constant, and getting hugging/compression resistance right on cell subviews is one of the most common real-world sources of the 'text is truncated when it shouldn't be' or 'cell height jumps around' bugs that Auto Layout debugging skills are used to track down.

Adding constraints to a view whose translatesAutoresizingMaskIntoConstraints is still YES (the default for a view created in code).

Set view.translatesAutoresizingMaskIntoConstraints = NO on every view before adding your own constraints to it.

With the flag left YES, Auto Layout keeps synthesizing its own constraints from the view's frame and autoresizing mask, which conflicts with any constraints you add yourself and produces confusing, hard-to-diagnose console warnings.

Leaving two views' size-defining constraints all at the required (1000) priority when they can genuinely contradict each other under some content or screen size.

Give the constraint you're willing to see broken a priority below 1000 on purpose, so the trade-off is intentional and silent rather than an unexpected console conflict warning.

A real 'Unable to simultaneously satisfy constraints' warning almost always means two constraints meant to be soft preferences were left at required priority; lowering the one that should yield turns an error into expected, controlled behavior.

Assuming a layout is correct because it looks right on the one device/orientation/content you happened to test.

Check hasAmbiguousLayout, or exercise ambiguity in the simulator, whenever a view's position or size isn't fully pinned down by explicit constraints or intrinsic content size.

An ambiguous layout can resolve to the frame you wanted purely by coincidence of the solver's internal order; nothing is actually pinning it there, and a different device, orientation, or content length can reveal the bug later.

Giving a title label a lower compression resistance priority than a secondary detail label, so the important text truncates first under pressure.

Give the label whose full text matters more the higher compression resistance priority, so it's the less important label that shrinks and truncates when space runs out.

Compression resistance priority — not source order or visual position — is what determines which of two competing views gives up width first; setting it backwards truncates the wrong label.

What does an NSLayoutConstraint fundamentally represent? A. A fixed pixel frame for a single view B. A linear equation relating a geometric attribute of one view to another view's attribute (or a constant) C. An animation curve applied to a view's position D. A callback invoked whenever a view resizes

B. A linear equation relating a geometric attribute of one view to another view's attribute (or a constant) — A constraint expresses a relationship — item1.attribute1 = multiplier × item2.attribute2 + constant — which Auto Layout's solver resolves alongside every other active constraint to derive each view's actual frame.

Why must translatesAutoresizingMaskIntoConstraints be set to NO before adding your own constraints to a view? A. It has no real effect and is purely a legacy formality B. It disables the view's intrinsic content size entirely C. Leaving it YES makes Auto Layout synthesize its own constraints from the view's frame, which conflicts with constraints you add yourself D. It is required only for views created in Interface Builder, never for views created in code

C. Leaving it YES makes Auto Layout synthesize its own constraints from the view's frame, which conflicts with constraints you add yourself — A view created in code defaults this property to YES, meaning Auto Layout auto-generates constraints from its frame and autoresizing mask; those synthesized constraints conflict with constraints you add by hand unless the flag is turned off.

A constraint has priority 1000. What does that mean? A. It is the very first constraint the solver evaluates B. It is a required constraint that must be satisfied, and cannot be broken in favor of a lower-priority one C. It applies only during animations D. It is ignored unless no other constraints are active

B. It is a required constraint that must be satisfied, and cannot be broken in favor of a lower-priority one — UILayoutPriorityRequired is 1000, the maximum priority; the solver treats required constraints as mandatory and will instead break a lower-priority constraint if the two are ever in conflict.

What is a view's intrinsic content size? A. The size the view was given in Interface Builder's canvas B. The view's natural, content-derived size that Auto Layout can use automatically when no explicit size constraint is given C. The maximum size a view is permitted to grow to under any circumstance D. A size that only applies to UIImageView, never to any other view class

B. The view's natural, content-derived size that Auto Layout can use automatically when no explicit size constraint is given — Views like UILabel, UIButton, and UIImageView compute a natural size from their own content; Auto Layout treats that intrinsic size as an implicit width/height constraint at the hugging/compression-resistance priorities, so you often don't need explicit size constraints at all.

Two labels sit side by side and together are wider than the space available. Which one truncates? A. Whichever label appears first in the source code, always B. Both truncate equally regardless of any priority settings C. The one with the lower horizontal compression resistance priority D. The one with the higher content hugging priority

C. The one with the lower horizontal compression resistance priority — Compression resistance priority determines which view gives up width first when space is insufficient; the label with the lower compression resistance priority on that axis is the one the solver shrinks (and which then visually truncates).

A layout looks correct in the simulator, but hasAmbiguousLayout returns YES for one of its views. What should you conclude? A. The check must be a false positive, since the layout visibly renders correctly B. The current frame is only one of several equally valid solutions; a different device, orientation, or content could resolve to a different, wrong frame C. The view has a conflict, not ambiguity, and one of its constraints has already been broken D. Ambiguity only matters for views with no intrinsic content size, so this can be safely ignored

B. The current frame is only one of several equally valid solutions; a different device, orientation, or content could resolve to a different, wrong frame — Ambiguity means the constraint set under-determines the frame; the solver still must produce some frame, and it can coincidentally match what you expected while remaining genuinely unpinned, which is exactly why 'it looks fine' is not proof the layout is correct.

You have a UILabel pinned to a superview's leading edge and top edge with two required constraints, and nothing else. Explain, in terms of ambiguity, what's missing, and add the anchor-based constraints needed so the label's frame is fully determined without adding any explicit width or height constraint.

Leading and top constraints alone are actually sufficient to make the label's frame unambiguous, because its intrinsic content size supplies both width and height automatically at the default hugging/compression-resistance priorities — no explicit width/height constraint is needed. What remains genuinely worth adding is a trailing constraint (e.g. constraintLessThanOrEqualToAnchor: superview.trailingAnchor) so long text is bounded rather than overflowing the superview, which the intrinsic size alone would not prevent.

A label has an intrinsic content size, so it doesn't need explicit width/height constraints — but leading+top alone still leaves something unresolved if you also expect it to respect a maximum width or wrap; think about what intrinsic content size alone does and doesn't pin down.