Вопрос проверяет знание основных техник dependency injection и понимание их плюсов и минусов на практике.
В iOS чаще всего используют внедрение через инициализатор, свойства или методы. Самый безопасный и явный способ — через инициализатор. Property injection применяют, когда зависимость опциональна или не может быть передана сразу. Реже используют сервис-локаторы и DI-контейнеры. Выбор способа зависит от жизненного цикла объекта и архитектуры проекта.
Внедрение зависимостей можно реализовать несколькими способами, и каждый из них подходит под разные сценарии.
Это предпочтительный способ в большинстве случаев.
final class UserViewModel {
private let repository: UserRepository
init(repository: UserRepository) {
self.repository = repository
}
}
Плюсы:
Зависимость обязательна и всегда валидна.
Объект не может существовать в некорректном состоянии.
Упрощает тестирование.
Минусы:
иногда неудобен для UIViewController, создаваемых storyboard.
Используется, когда зависимость не является обязательной на момент создания объекта.
final class ProfileViewController: UIViewController {
var analytics: AnalyticsTracking?
}
Плюсы:
Гибкость.
Подходит для storyboard/XIB.
Минусы:
риск забыть установить зависимость;
сложнее гарантировать корректное состояние.
Применяется реже и обычно для разовых зависимостей.
func configure(with service: SomeService) {
self.service = service
}
Подходит, когда:
зависимость используется только в одном сценарии;
нет смысла хранить ее постоянно.
Объект сам запрашивает зависимость из общего контейнера.
let service = ServiceLocator.resolve(UserService.self)
Минусы:
Скрытые зависимости.
Усложнение тестирования.
Повышенная связность.
Используются в крупных проектах.
Особенности:
Централизованная регистрация зависимостей.
Автоматическое разрешение графа объектов.
Дополнительная сложность и магия.
В большинстве iOS-проектов достаточно initializer injection. Property injection стоит использовать осторожно, а DI-контейнеры — только при реальной необходимости