Выполнение HTTP
запросов — это один из самых важных навыков, которые необходимо получить при изучении iOS
. В более ранних версиях Swift
( до версии 5) вне зависимости от того, формировали ли вы эти запросы «с нуля» или с использование известного фреймворка Alamofire
, вы в конечном итоге получали сложный и запутанный код с callback
типа completionHandler: @escaping(Result<T, APIError>) -> Void
.
Появление в Swift 5
нового фреймворка функционального реактивного программирования Combine
в сочетании с уже существующими URLSession
и Codable
предоставляет вам все необходимые инструменты для самостоятельного написания очень компактного кода для выборки данных из интернета.
Мы будем создавать «издателей» Publisher
для выборки данных из интернета, на которые в дальнейшем можно будет легко «подписаться» и использовать при проектировании UI
как с помощью UIKit
, так и с помощью SwiftUI
.
В SwiftUI
это выглядит более эффектно, если не сказать «фантастически», так как разделение данных и View
в SwiftUI
осуществляется с помощью ObservableObject
классов с @Published
свойствами, изменения которых SwiftUI
АВТОМАТИЧЕСКИ отслеживает и полностью «перерисовывает» View
. В эти ObservableObject
классы можно заложить определенную бизнес-логику приложения, так как некоторые из этих @Published
свойств могут напрямую меняться такими «активными» элементами пользовательского интерфейса (UI
) как текстовые поля TextField
, Picker
, Stepper
, Toggle
и т.д. Другие @Published
свойства, напротив, могут быть «пассивными», являясь результатом синхронных и/ или асинхронных преобразований «активных» @Published
свойств, но именно они то нас чаще всего и интересуют. Они обычно воспроизводятся в SwiftUI
такими пассивными (UI
) элементами, как текст Text
, изображение Image
, геометрические фигуры и т.д. Зависимость «пассивных» @Published
свойств от «активных» @Published
свойств очень просто описать с помощью Combine
.
Чтобы было понятно, о чём идет речь, приведу конкретные примеры. Сейчас многие сервисы типа базы данных фильмов TMDb или агрегаторов новостей NewsAPI.org и Hacker News предлагают пользователям выбирать различные коллекции фильмов или наборы статей в зависимости от того, что вас интересует. В случае базы данных фильмов TMDb это могут быть фильмы, которые идут в данный момент в кинотеатрах, или популярные фильмы, или топовые фильмы, или фильмы, которые скоро появятся на экране. В случае агрегаторов новостей NewsAPI.org и Hacker News это могут быть последние новости, или новости в какой-нибудь категории — «спорт», «здоровье», «наука», «технологии», «бизнес», или новости от определенного информационного источника «CNN», «ABC news», «Bloomberg» и т.д., или новости, удовлетворяющие какому-то произвольному критерию. Свои желания для сервисов вы обычно «высказывает» в виде Endpoint
, который формирует для вас нужный URL
.
Так вот, используя фреймворк Combine
, вы можете в ObservableObject
классах с помощью очень компактного кода (в большинстве случаев не более 10-12 строк) однократно сформировать синхронную и/или асинхронную зависимость списка фильмов или статей (как «пассивных» @Published
свойств) от Endpoint
(как «активных» @Published
свойств) в виде «подписки», которая будет действовать на протяжении всего «жизненного цикла» экземпляра ObservableObject
класса. А далее в SwiftUI
управлять только тем, что вы хотите увидеть, то есть выбирать нужную вам Endpoint
: то ли это будут популярные фильмы, или фильмы, идущие в данный момент на экране, то ли это будут статьи с последними новостями или статьи в разделе «здоровье». Появление соответствующих фильмов или статей на вашем UI
будет обеспечиваться АВТОМАТИЧЕСКИ этими ObservableObject
классами и их пассивными @Published
свойствами. В коде SwiftUI
у вас никогда не возникнет необходимости явно запрашивать выборку фильмов или статей, вы будете управлять только тем, ЧТО вы хотите увидеть через Endpoint
, вовсе не заботясь о результате, ибо он ВСЕГДА будет правильным и синхронным благодаря работе ObservableObject
классов, которые исполняют роль View Model
.
Я на трех конкретных примерах покажу, как это работает с помощью применения Combine
для формирования HTTP
запросов к различным сервисам и использование их в качестве View Model
в SwiftUI
.
Начнем с разработки приложения для взаимодействия с базой данных фильмов TMDb, а в последующем — приложений для взаимодействия с агрегаторами новостей NewsAPI.org и Hacker News. Во всех трех случаях будет действовать примерно одна и та же схема использования Combine
, ибо в приложениях такого рода всегда приходится формировать СПИСКИ фильмов или статей, выбирать сопровождающие их «КАРТИНКИ» (images
), ИСКАТЬ в базах данных нужные фильмы или статьи с помощью поисковой строки.
При обращении к сервисам типа базы данных фильмов TMDb или агрегаторов новостей NewsAPI.org и Hacker News могут возникать ошибки, например, связанные с тем, что вы задали неправильный ключ API-key
или превысили допустимое количество запросов или еще что-то. Необходимо обрабатывать такого рода ошибки сервиса. Иначе пользователь вашего приложения попадёт в ситуацию, когда вдруг ни с того, ни с сего перестанут обрабатываться какие-либо запросы, оставляя пользователя в полном недоумении с пустым экраном. Поэтому надо уметь не только выбирать с помощью Combine
данные из интернета , но и сообщать об ошибках, которые могут возникнуть при выборке. В этой статье мы уделим внимание обработке ошибок такого рода в Combine
.