Какие алгоритмы использовать для рекурсивного поиска по иерархии вью
Что проверяют
Видите ли вы в иерархии UIView обычное дерево и умеете ли выбрать обход под задачу. Следом обычно просят написать поиск первой вью нужного типа или по accessibilityIdentifier и спрашивают, чем на практике отличаются DFS и BFS.
Как отвечать
У каждой вью один superview и массив subviews, значит, работают классические обходы дерева:
- DFS (в глубину): рекурсия по
subviewsили цикл с явным стеком. Уходит в ветку до конца, прежде чем перейти к соседу. Удобен для задач «собрать все вью типа X»; - BFS (в ширину): очередь, обход по уровням. Первое совпадение окажется ближайшим к корню, это полезно, когда подходящих элементов несколько и нужен самый внешний;
- подъём вверх: цепочка
superviewдо корня, например найти ячейкуUITableViewCellдля кнопки внутри неё. Стоит O(глубина), а не O(n).
Оба обхода вниз стоят O(n) по числу вью. Переполнение стека от рекурсии на реальных экранах маловероятно, глубина иерархии измеряется десятками уровней, но итеративная версия снимает вопрос совсем.
Ищут почти всегда не конкретный экземпляр, а по условию, поэтому покажите обобщённую сигнатуру: func firstSubview<T: UIView>(of type: T.Type) -> T? или вариант с предикатом (UIView) -> Bool. Для очереди в BFS не берите removeFirst() у массива, он сдвигает все элементы и стоит O(n). Держите индекс головы или возьмите Deque из пакета swift-collections. Заодно упомяните встроенный viewWithTag(_:): он уже ищет по поддереву, включая саму вью.
Где спотыкаются
Пишут поиск через == с заранее известной вью. Такой код ничего не находит, ведь ссылка на вью уже есть. Задача интервьюера про предикат: тип, тег, идентификатор.
Заявляют O(n) для BFS, а в коде стоит removeFirst(). На широких уровнях обход становится квадратичным, и внимательный интервьюер это заметит.
Обходят иерархию на каждом layoutSubviews или вне главного потока. UIKit трогают только с главного потока, а полный обход на каждый кадр обходится дорого. В рабочем коде ссылку на нужную вью хранят, а поиск по дереву оставляют для тестов, отладки и чужих контейнеров.