Сетевой уровень - очень распространенная и важная часть современных мобильных приложений. Обычно он принимает форму класса менеджера, который заботится о каждом сетевом запросе в вашем приложении.

Учитывая разделение задач, хороший сетевой уровень обычно не связан с кодом представления. Логические контроллеры или контроллеры представлений используют диспетчер сети для запроса определенных вызовов API, например, и впоследствии получают обратный вызов, когда запрос завершается успешно или не может отразить результат представлениям. Поэтому в идеале сетевой менеджер никогда не должен ничего знать о представлениях.

Проблема

Это уникальная ситуация, которая затрудняет разделение проблем. Когда вы получаете сообщение об ошибке из сети, например 404 или 500, и вам нужно показать пользователю какие-то предупреждения с правильным сообщением об ошибке. Эта ошибка должна отображать один и тот же пользовательский интерфейс независимо от того, где вызывается этот сетевой менеджер. Код часто находится в одном месте и обычно является корневым контроллером представления всего приложения. Как получить ссылку на корневой контроллер представления из диспетчера сети, когда диспетчер сети вызывается из контроллера представления в глубине иерархии представлений?

UIAapplication

Наиболее распространенный метод обращения к контроллеру корневого представления - использование UIApplication. Вы можете получить доступ к контроллеру корневого представления, используя UIApplication вот так:

Однако UIApplication.shared по-прежнему является экземпляром представления, и не рекомендуется обращаться к нему из диспетчера сети. Более того, сложно написать модульный тест с экземпляром UIApplication непосредственно из диспетчера сети.

Уведомление

Уведомление - еще один способ решить эту проблему. Вы можете наблюдать уведомление от контроллера корневого представления и запускать уведомление от сетевого менеджера. Использование уведомлений - простое решение многих проблем, но за него приходится платить. Вы можете вызвать уведомление из любого места, независимо от того, от контроллера ли оно или от кода представления. Более того, он относительно подвержен ошибкам, и его довольно сложно отладить. Конечно, вы МОЖЕТЕ писать модульные тесты с уведомлением, используя внедрение зависимостей, но прохождение модульного теста не гарантирует надежности уведомления.

Цепочка ответчика

Недавно я услышал о Responder Chain и, наконец, решил покопаться в нем, быстро поняв, что он очень хорошо подходит для этой проблемы.

Цепочка респондентов в чем-то похожа на Уведомление, но с некоторыми ключевыми отличиями. Цепочка респондентов - это иерархия UIReponder подклассов, которая включаетUIView. Если вы отправляете сигнал в цепочку респондента, он отправляет его первому респонденту, а затем продолжает движение по цепочке респондента, пока не найдет ответчика, который может выполнить действие - или пока он не достигнет AppDelegate.

А если вы используете метод UIApplication.sendAction, вы можете отправить действие определенной цели. Таким образом, мы можем использовать это для отправки определенного действия контроллеру корневого представления в любое время.

Мы также можем сделать наш код сетевого менеджера тестируемым, используя протокол Swift и внедрение зависимостей.

Код

Ответственный

Я создаю абстракцию под названием Respondable. Это просто протокол Swift, и мы можем использовать его для имитации экземпляра UIApplication.

И тогда мы можем написать UIApplication расширение, соответствующееRespondable.

И вы можете использовать внедрение зависимостей в диспетчере сети, чтобы иметь возможность имитировать объект Respondable в наших модульных тестах.

Вывод

Responder Chain изначально спроектирован так, чтобы заботиться о взаимодействиях с пользователем, таких как прикосновения, но он также может быть очень мощным в определенных ситуациях, подобных нашему примеру выше.

В этом примере мы указали цель как корневой контроллер представления, но если вы не укажете цель в UIApplication.sendAction, она отправит действие первому респонденту или любому UIResponder подклассу, который отвечает на действие. По сравнению с уведомлениями, Responder Chain - очень удобный API, который позволяет писать менее хрупкий и более тестируемый код.