frame vs bounds

UIKit Junior Swift 5.0+ iOS 17+ Reviewed By Alok Singh

Predict the output

What does this print (rounded)?

let v = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
v.transform = CGAffineTransform(rotationAngle: .pi / 2)
print(v.bounds.width, v.frame.width)
Options
Hint 1 of 1

Which one is in the superview's coordinates?

Choose an answer, then open Show answer below to check it.

Show answer

Answer: B 100 50

Correct. bounds keeps the view's own size; the rotated bounding box is 50 wide.

Why not the others?
  • A 100 100. frame is the bounding box after rotation, so its width changes.
  • C 50 50. Transforms don't change bounds.
  • D 50 100. That swaps which one changes.

30-second answer

bounds is the view's own coordinate space: its origin (usually zero) and size. frame is the view's position and size in its superview's coordinates. After a transform such as rotation, frame becomes the bounding box of the transformed view and is not meaningful to set; bounds and center still describe the view.

Practise saying it · 30 s. No recording, just a timer

Explain frame vs bounds.

Say your answer out loud, then check which of these points you covered:

  • bounds = own coordinates
  • frame = superview coordinates
  • frame is a bounding box after transforms

Deep dive

Changing bounds.origin scrolls the content, which is how UIScrollView works.

Don't set frame on a transformed view; set bounds and center.

Convert between spaces with convert(_:to:).

Auto Layout sets frames for you; read sizes in layoutSubviews.

Common mistakes

  • Reading frame.width after a rotation and expecting the original width.
  • Setting frame on a transformed view.

Senior take & follow-ups

Seniors explain the two coordinate spaces and the transform caveat.

Follow-up questions

Think of your answer first, then open the hint.

  1. What does bounds.origin do in a scroll view?

    Show hint

    It is the content offset.

  2. How do you get a view's rect in window coordinates?

    Show hint

    view.convert(view.bounds, to: nil).

Suggest a fix if something here is wrong or out of date.