Как организовать взаимодействие между двумя классами без прямого знания друг о друге
Что проверяют
Понимаете ли вы разницу между «не знать о классе» и «не знать ни о чём»: связь всё равно есть, вопрос в том, через какую абстракцию и кто её настраивает. Следом почти всегда спрашивают, как при этом не получить утечку памяти.
Как отвечать
Общий принцип: классы зависят от протокола или канала событий, а соединяет их третий объект, координатор, фабрика или DI-контейнер. Инструменты по типу связи:
- delegate через протокол: один к одному, классика UIKit. Протокол ограничен
AnyObject, свойство объявленоweak var delegate: ListDelegate?; - замыкание:
var onSelect: ((Item) -> Void)?для одного события без отдельного протокола. Внутри нужен[weak self]; - внедрение зависимости: класс принимает в
initпротоколDataProviding, реализацию передаёт сборщик модуля, в тестах подставляется заглушка; - Combine и Swift Concurrency:
PassthroughSubjectили@Publishedдля потока событий,AsyncStreamдля той же идеи в async/await. С iOS 17 для состояния в SwiftUI есть макрос@Observable; NotificationCenter: один ко многим, отправитель не знает получателей. Годится для системных событий, но поток данных становится неявным;- Mediator или Coordinator: посредник знает обоих и соединяет их, сами участники друг о друге не знают. Типичный пример: координатор навигации.
Выбор объясните так: один получатель и одно событие дают delegate или замыкание, поток значений даёт Combine или AsyncStream, широковещательные события уходят в NotificationCenter.
Где спотыкаются
Объявляют делегат сильной ссылкой или забывают [weak self] в замыкании. Контроллер держит объект, объект держит контроллер, и оба не освобождаются.
Кладут протокол в модуль реализации. Потребитель тогда импортирует этот модуль ради интерфейса, и независимости нет: протокол должен принадлежать тому, кто его использует.
Строят всё на NotificationCenter со строковыми именами. Кто кого вызывает, находится только поиском по проекту, а опечатка в имени уведомления рвёт связь без единой ошибки компиляции.