Проект с Dependency Injection похож на елочную гирлянду — он красив, радует детей и взрослых. Но если где-то не внедрить зависимость, отключится целый сегмент приложения. И, чтобы найти источник проблем, придется проверять все зависимости в этом сегменте. В этой статье описаны несколько вариантов поиска пустых зависимостей. А в нашем репозитории есть небольшая библиотека, которая поможет в этом: TinkoffCreditSystems/InjectionsCheck  Объявить все зависимости как non-optional и внедрить их в Init — это самый надежный способ.  Плюсы: Минусы: Можно использовать тесты, чтобы проверить, все ли зависимости на месте. Но следить за ними сложнее, чем за объектами, поэтому нужен простой способ поддерживать такие тесты в актуальном состоянии. С этим поможет функция, которая проверяет все optional-свойства объекта и сообщает об ошибке, если находит nil. Чтобы быть уверенными, что тесты не пропустят пустые зависимости, необходимо заставить их проверять всё, кроме зависимостей из списка исключений. Проще поддерживать список исключений, чем список свойств, которые надо проверять. Если исключение не будет прописано, тест провалится, и это будет заметно. Плюсы: Минусы: В Swift эту функцию можно создать с помощью рефлексии и класса Mirror. Он позволяет обойти все свойства и посмотреть их значения. label: String — имя свойства,
value: Any — значение, которое может быть nil. Но есть одна неприятность: Swift не дает сравнить Any с nil. Формально он прав, ведь «Any» и «Any?» — разные типы. Поэтому нужно снова воспользоваться классом Mirror, чтобы найти в Any финальный Optional и узнать, равен ли он nil. Рекурсия используется из-за того, что в Any может быть вложенный Optional, например, IService??.. Результат этой функции выдаст обычный Optional, который можно сравнить с nil.  Для некоторых объектов не все свойства нужно проверять на nil, поэтому добавим список свойств-исключений. Из-за того, что child.label — это строка, задать исключения можно только так: Swift 4 KeyPath позволяет получить значение по ключу — объекту, а не строке. Сейчас невозможно получить имя свойства в виде строки. И нельзя получить полный список всех KeyPath, чтобы пройтись по ним. Используем протокол SelectorName, чтобы поддержать все варианты без приведения типа, а также enum:  Итоговый код функции для проверки внедрения зависимостей будет выглядеть так: Зависимости можно объявить как Force unwraped: Плюсы: Минусы: Падение приложения создает негативный пользовательский опыт. Как в примере с гирляндами: получится лампочка, которая ярко взрывается, если перегорает. Скорее всего, такая пустая зависимость пройдет мимо разработчика и тестировщика, если она отвечает за не очень важную или редко используемую функцию, а приложение способно работать, хоть и с ограниченной функциональностью.  Например, без форматировщика номера телефона в списке заказов приложение будет работоспособно, выведет остальную информацию, а не упадет. И, конечно же, сообщит разработчикам о проблеме. В Swift есть условная компиляция, что позволяет использовать философию Force unwrapped-зависимостей только в Debug-режиме. Условия компилятора позволяют сделать функцию, которая вызовет fatalError в режиме отладки, если найдет пустые зависимости. И ее удобно использовать на выходе из сервис-локатора, Assembly или фабрики.  Плюсы: Минусы: Эта функция-обертка проверяет зависимости объекта и роняет его с ошибкой, если для компилятора задан флаг -DDEBUG или -DINJECTION_CHECK_ENABLED. В остальных случая тихо пишет в лог: У всех способов есть свои плюсы и минусы. В зависимости от проекта, команды, устоявшихся принципов работы будет лучше работать тот или иной способ. Я предпочитаю не внедрять зависимости через Init, потому что так невозможно внедрить во ViewController зависимости, которые создаются из Storyboard. И это усложняет рефакторинг и внесение изменений. Forced Unwrap не используется не только для управления зависимостями, но и в production вообще. У SwiftLint даже активировано правило ‘force_unwrapping’, которое не дает его использовать. Проверка зависимостей в тестах хорошо работает для поддержки старого кода. Гарантирует, что старые зависимости не пропали, и все продолжает работать. Но неудобна для текущей разработки. Поэтому я предпочитаю проверку на выходе из DI-контейнера с падением в Debug-режиме. Так быстрее всего можно обнаружить пустые зависимости и сразу их исправить. Все представленные здесь функции есть в библиотеке:
TinkoffCreditSystems/InjectionsCheck Руководитель мобильной разработки в OZON Fintech