Check if a subview is in a view
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In UIKit, checking whether one view is "in" another can mean two different things: the view is a direct child in the subviews array, or it is anywhere inside the ancestor's hierarchy. Those cases need different APIs.
If you only check subviews.contains, you will miss grandchildren and deeper descendants. In most practical code, what you really want is "is this view a descendant of that container?"
Direct Subview vs Descendant
Every UIView has a subviews array containing only its immediate children. That means this check works only for direct containment:
This returns true only when childView.superview === parentView.
If the hierarchy is:
then parentView.subviews.contains(childView) is false because childView is not a direct subview of parentView.
Best Option: isDescendant(of:)
UIKit already has the method most developers want:
This returns true for direct children, grandchildren, and any deeper nested view in the same subtree.
Here is a complete example:
That makes the intent explicit and avoids manual tree traversal.
Checking by Walking the superview Chain
If you need custom logic, you can walk upward through the superview chain yourself:
Usage:
This is useful when you want to stop early, collect the full ancestor path, or combine the containment test with other conditions.
When Identity Matters
Use identity comparison, not value comparison. UIView is a reference type, so the question is whether two variables point to the same view object.
In Swift, that means using ===:
Using == is the wrong mental model here. You are not comparing two data values; you are comparing object identity in the hierarchy.
Practical Cases
This check appears in several common situations:
- preventing duplicate
addSubviewoperations - deciding whether to move a view to a different container
- verifying a reusable cell or overlay is still mounted
- debugging Auto Layout problems by confirming which container owns a view
For example:
That avoids adding the same overlay repeatedly during state updates.
Why Not Search the Whole Tree Manually
You can recurse through every subview under parentView, but that is usually the wrong direction. If you already have the candidate child view, walking upward through superview is simpler and often cheaper because the chain length is usually shorter than the full subtree size.
Searching downward only makes sense when you know the ancestor and are trying to find a matching descendant by some property, such as a tag, identifier, or custom class.
Common Pitfalls
The most common mistake is using parentView.subviews.contains(childView) when the real question is whether the child appears anywhere in the hierarchy. That only tests direct children.
Another mistake is checking containment before the view has actually been inserted into the hierarchy. A newly created view has superview == nil, so any containment test will be false.
Developers also sometimes compare views using == instead of ===. For view hierarchy checks, identity is the correct comparison.
Finally, remember that hierarchy changes must happen on the main thread. If UI state is being mutated from background code, containment checks can become unreliable and the app may crash.
Summary
- '
subviews.containschecks only direct children.' - '
isDescendant(of:)is the simplest way to test whether a view is anywhere inside another view.' - Walking the
superviewchain is a good custom alternative. - Use
===when comparing view objects by identity. - If you already have the child view, walking upward is usually better than recursively scanning downward.
- Run view hierarchy logic on the main thread to keep UIKit state consistent.

