Преодолеть основное ограничение Swift для протокола

Расширения протокола спешат на помощь!

Эта статья содержит для вас реальный пример, который используется в рабочих приложениях. Не говорите, что я вас не балую (потому что не балую).

Сложность: Начинающий | Легко | Нормальный | Испытывающий

Предпосылки:

  • Уметь создать Hello, World! Приложение для iOS (руководство ЗДЕСЬ)
  • Использование расширений в Swift (руководство ЗДЕСЬ)
  • Использование протоколов в Swift (Руководство ЗДЕСЬ)

Терминология

Расширения: расширения добавляют новые функции к классу, структуре, перечислению или протоколу.

Проблема

Когда вы используете функцию или инициализируете класс, вы вполне можете использовать аргументы по умолчанию.

Это невероятно полезно, и я использовал именно такую ​​функцию, когда создавал Network Manager, и это дает довольно удобный пример для остальной части этой статьи.

Теперь я хочу, чтобы это работало с REST API, то есть я хотел бы, чтобы это работало для GET, POST, PUSH, PUT, DELETE и PATCH - но для некоторых из них вам может потребоваться предоставить данные в теле запроса. Однако для GET запроса мы не должны добавлять никаких данных.

Итак, если мы создадим протокол (который помогает обеспечить хорошее тестирование, и именно так мы должны кодировать приложения Swift в конце концов) следующим образом:

мы сможем получить доступ к выборке только в том случае, если предоставим данные, и, что еще хуже, токен. Но я не хочу использовать токен в своем многоразовом сетевом уровне!

Вы можете попробовать использовать аргументы по умолчанию, и это будет хорошей стратегией:

которые мне кажутся немного сложными для чтения как Gist, поэтому вот еще одно представление того же кода (в блоке кода!):

func fetch(url: URL, method: HTTPMethod, headers: [String : String], token: String? = nil, data: [String: Any]?, completionBlock: @escaping (Result<Data, Error>) -> Void)

обратите внимание, что здесь есть только одно небольшое изменение - добавление = nil к параметру токена. Это дает следующую ошибку:

Default argument not permitted in a protocol method

Какая катастрофа! Итак, как мы можем решить эту проблему?

Решение - использовать расширение протокола!

Вот в чем загвоздка - вы можете добавить аргументы по умолчанию в расширение протокола!

Вот полный протокол NetworkManagerProtocol, как в классе Network Manager (который дает пример реализации расширения для реализации аргументов по умолчанию в протоколе):

Теперь к этому можно получить доступ через протокол, где вам нужно предоставить заголовок и токен ИЛИ вы можете сделать это через расширение (и обратите внимание, что расширение также вызывает подпись основного протокола и просто заполняет эти аргументы по умолчанию).

Вот два способа использования этих аргументов - разве это не круто?

nil представлен здесь как вариант, но мы можем полностью исключить эти параметры, чтобы получить очень четкий и легкий для чтения фрагмент кода:

Заключение

Из-за того, как работает Swift, вы не можете добавлять аргументы по умолчанию в метод протокола. Это создает немало проблем, поскольку мы часто хотим использовать аргумент по умолчанию, даже если мы соответствуем протоколу. Но есть способ добиться результата:

Вы можете использовать их в расширениях протокола.

Есть целый ряд ситуаций, в которых это может быть полезно, и в этой статье вы рассмотрели один из моих примеров.

Теперь я надеюсь, что статья вам помогла, и что у вас все хорошо в процессе программирования.

Если у вас есть вопросы, комментарии или предложения, пишите мне в Twitter.