Современный код для выполнения HTTP запросов в Swift 5 с помощью Combine и применение его в SwiftUI. Часть 1. База данных фильмов.

Выполнение 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.

Читать далее

API для удаленной асинхронной выборки с помощью Apple Combine.

Combine — это функционально реактивный Swift фреймворк, который недавно реализован для всех платформ Apple, включая Xcode 11. С помощью Сombine очень легко обрабатывать последовательности значений values во времени. Он также позволяет упростить асинхронный код, отказавшись от делегирования и сложных вложенных callbacks.

Но изучение самого фреймворка Сombine на первых порах может показаться не таким уж простым. Дело в том, что основными «игроками» Сombine являются такие абстрактные понятия как «издатели» Publishers, «подписчики» Subscribers и операторы Operators. Есть, конечно, и другие, но без понимания этих 3-х не удастся много достигнуть в понимании логики функционирования Combine. Поэтому статья начинается с очень краткого обзора этих основных понятий. А далее нас ждет приятный сюрприз от Apple. Большинство»издателей» Publishers, «подписчиков» Subscribers и операторов Operators либо уже реализованы в самом Combine, либо они добавлены к уже существующим классам UISession, Timer, NotificationCenter, CoreData. И это существенно облегчает написание кода, который оказывается очень компактным и хорошо читаемым. Вы увидите это на примере приложения, связанного с асинхронной выборкой информации о фильмах из очень популярной сейчас базы данных TMDb. Мы создадим  два различных приложения: UIKit и SwiftUI, и покажем, как с ними работает Combine.

Надеюсь, эта статья облегчит Вам изучение Сombine.

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

Читать далее

SwiftUI & Combine: Вместе лучше.

Это перевод статьи «SwiftUI & Combine: Better Together», в которой на очень простом примере и очень подробно показано, как можно использовать новый фреймворк Combine в содружестве со SwiftUI с целью эффективного создавать приложений с помощью функционального реактивного программирования (Functional Reactive Programming — FRP) .

Одно из самых значимых объявлений, сделанных Apple на конференции разработчиков WWDC 2019, был SwiftUI — его декларативный подход позволяет создавать пользовательские интерфейсы (UI) очень быстро, так что не удивительно, почему разработчики так воодушевлены этим. Однако скрытой жемчужиной WWDC 2019 был фреймворк Combine, который не получил столько фанфар, но я думаю, что он бы это заслужил.

Apple дала одобрение на функциональное реактивное программирование, и вскоре это уже не будет технологией, которую используют лишь отдельные группы разработчиков.

Читать далее

SwiftUI для конкурсного задания Telegram Charts (март 2019 года). Часть 2.

Это вторая часть поста, посвященного использованию SwiftUI для решения предыдущего конкурса Telegram Charts (март 2019).

Первая часть, в которой сформулирована сама задача и описаны отдельные элементы UI для отображения одного «набора Графиков»,  представлена здесь. В этом посте мы займемся комбинированием этих частей сначала для создания ChartView для одного «набора Графиков», а затем для комбинации различных ChartView для множества «набора Графиков».

Комбинирование различных Views

SwiftUI — это прежде всего комбинирование различных маленьких Views в большие, а больших Views — в очень большие и т.д., как в игре Lego. В SwiftUI есть множество средств такого комбинирования Views:

  • вертикальный стек VStack,
  • горизонтальный стек HStack,
  • «глубинный» стек ZStack,
  • группа Group,
  • ScrollView,
  • список List,
  • форма Form,
  • контейнер с «закладками» TabView
  • и т.д.

Начнем наше комбинирование с самого простейшего GraphsViewForChart, который наделяет «безликий» «набор Графиков» GraphsForChart осью Y и индикатором, перемещающимся по оси X, с помощью «глубинного» стек ZStack: Читать далее

SwiftUI для конкурсного задания Telegram Charts (март 2019 года). Часть 1.

Сразу начну с замечания о том, что приложение, о котором пойдет речь в этой статье, требует Xcode 11 и MacOS Catalina (в настоящий момент последняя находятся в Beta 9). Код приложения находится на Github.

В этом году на WWDC 2019, Apple анонсировала SwiftUI, новый способ построения пользовательского интерфейса (UI) на всех устройствах Apple. Это практически полное отступление от привычного нам UIKit, и я — как и многие другие iOS разработчики — очень хотела посмотреть этот новый инструмент в действии.

Очень много было написано о SwifUI за последние три месяца, начиная с Xcode 11 beta 1 и до  нынешней версии Xcode 11.0. Этот пост вовсе не имеет целью дать какое-то масштабное введение в SwiftUI. Это просто опыт решение некоторой задачи, которую не удается в рамках UIKit удовлетворительно решить (представить код в читабельном виде).

Задача связана с конкурсом, объявленным Telegram для Android, iOS and JS разработчиков, который  проходил в период 10 — 24 марта 2019 года.  В этом конкурсе была предложена простая задача графического отображения интенсивности использования некоторого ресурса в интернете от времени на основе JSON данных.

Читать далее

Только что прочитанный курс CS193P Весна 2019 не будет выложен в iTunes для публичного доступа.

5 июня 2019 года профессор Пол Хэгерти закончил читать очередной Стэнфордский курс CS193P «Разработка iOS приложений» Весна 2019 для Swift 5 и iOS 12, но на этот раз, со слов самого профессора, ни команда iTunes, ни Apple не проявили интереса к тому, чтобы записать этот курс на видео, и он не будет выложен в iTunes для публичного изучения. Хотя, конечно, курс CS193P Весна 2019 записывался на видео непосредственно командой Стэнфорда и был доступен исключительно студентам Стэнфорда.

После того, как с 3 по 8 июня 2019 года прошла конференция разработчиков Apple WWDC 2019, стало приблизительно понятно, почему  это произошло с курсом CS193P «Разработка iOS приложений» Весна 2019.

Во-первых, на конференции разработчиков Apple предложила ряд абсолютно новых технологий разработки iOS (а также watchOS, tvOS и MacOS) приложений, и это прежде всего разработка пользовательского интерфейса (UI) на языке Swift 5.1 с использованием фреймворков SwiftUI и Combine, совершенно новая операционная система iPadOs, а также возможность адаптировать iPad-приложения на MacOS с помощью Catalyst.

iPadOS основана на тех же принципах, что и iOS, но её уникальные возможности просто поражают.

Проект Catalyst для новой операционной системы macOS 10.15 Catalina — это ранее известный проект под кодовым названием «Marzipan». И это тоже совершенно новый способ портировать iPad-приложения на Mac.

Так что Apple предлагает разработчикам приложений на своих устройствах совершенно новые супер современные подходы. Профессору Полу Хэгерти придется разрабатывать совершенно новый курс  CS193P «Разработка iOS (iPadOS??) приложений». Впрочем, он всегда это делает очень оперативно и эффективно. Вспомним хотя бы, как он оперативно рискнул перейти от Objective-C на самую первую версию Swift 1.0 (конечно, сильно сырую в то время) и самым первым выпустил обучающий курс «Разработка iOS приложений на Swift«. Надеюсь, так же будет и на этот раз, и мы в начале 2020 года увидим новый адаптированный к новым реалиям курс CS193P «Разработка iOS (iPadOS??) приложений». Но пока на сайте Stanford‘а нет расписания на 2020 год.

Во-вторых, еще одно новшество, объявленное Apple на конференции разработчиков  WWDC 2019 для новой операционной системы macOS 10.15 Catalina , — это разделение приложения iTunes, в котором профессор Пол Хэгерти размещал материалы своего курса для скачивания, на 3 отдельных приложения: Apple Music — для музыки, Apple TV — для TV и фильмов и Apple Podcasts — для подкастов, где собственно и находятся материалы для курса CS193P «Разработка iOS 11 приложений» Осень 2017 и могут быть скачаны:

Материалы для будущих курсов CS193P вряд ли будут размещаться в Apple Podcasts, так как все-таки у этого приложения другое предназначение.

Пока профессор создает свой новый курс CS193P, стоит подготовиться к разработке iOS приложений с помощью очень интересного фреймворка  SwiftUI. В связи с этим я планирую разместить на этом сайте ряд уроков по SwiftUI, которые направлены на разработку приложения, отображающего информацию о пользователях некоторого ресурса, полученную в JSON формате, в виде временных графиков. Это было конкурсное задание Telegram, и я покажу, как просто оно решается с помощью SwiftUI.

В ближайшие пару дней выложу это, пока еще не конца реализованное, но уже прилично работающее, приложение на Github.

Обновление демонстрационных примеров и решений Заданий курса CS193P Fall 2017 до Swift 4.2 и iOS 12

Вышли официальные версий Swift 4.2iOS 12 и Xcode 10.  Поэтому я решила на своем сайте обновить демонстрационные примеры, сопровождающие замечательный стэнфордский курс  CS193P Fall 2017-2018 «Developing  iOS 11 Apps with Swift»,  для  Swift 4.2 и iOS 12.

В результате этого я пришла к ВЫВОДУ.


Если вы изучаете стэнфордский курс CS193P Fall 2017-2018 «Developing  iOS 11 Apps with Swift», то смело открывайте Xcode 10 и создавайте проекты для iOS 12 на Swift 4.2. Весь код, который предлагает профессор, будет прекрасно работать.


Демонстрационные примеры для Swift 4.2, iOS 12 и Xcode 10 находятся на Github.

Решения Заданий  для курса CS193P Fall 2017  «Developing  iOS 11 Apps with Swift» для Swift 4.2, iOS 12 и Xcode 10 находятся на Github.

Надо сказать, что большинство демонстрационных примеры не претерпели никаких изменений в коде для Swift 4.2 и iOS 12 за исключением 1 или 2-х методов в файле AppDelegate.swift, о которых я расскажу ниже.

Читать далее

Задание 6 Stanford CS 193P Fall 2017. Галерея изображений Image Gallery с постоянным хранением (persistent). Решение.

Содержание

Текст Домашнего задания на английском языке доступен на  iTunes в пункте “Programming: Project 6: Persistent Image Gallery″. На русском языке вы можете скачать Задание 6 здесь: «Задание VI: Галерея изображений Image Gallery с постоянным хранением (persistent)»

Для решения Задания 6 необходимо ознакомиться с Лекцией 7, Лекцией 11Лекцией 12 , Лекции 13 и Лекцией 14.

Цель этого Задания 6 — понять  работу FileManager, URL, Codable, UIDocument и UIDocumentBrowserViewController и изучить, как пользоваться iOS API полностью самостоятельно по документации.

Это Задание использует код, который вы создали в Задании 5, но, возможно, вы захотите начать новый Xcode проект “с нуля” (так что вы сможете использовать Document Base App шаблон).

Мое решение обязательных и допонительных пунктов Задания 6 находится на Github  для iOS 11 и на Github для iOS 12:

ImageGallery_6_Requied_OLD — сохранение Модели в файловой системе без UIDocumentBrowserViewController

ImageGallery_6_Requed_Browser— подключение UIDocumentBrowserViewController, но пока присутствует кнопка «Sav

ImageGallery_6_Requed_Browser_No_Save_Button — работает UIDocumentBrowserViewController, но НЕТ кнопки «Save», используется URLCache,

ImageGallery_6_Requed_Browser_No_Save_Button_LocalImage — присутствует UIDocumentBrowserViewController, НЕТ кнопки «Save«, используется URLCache, сохранение изображений, для которых нет URL, производится в локальной файловой системе, документ имеет свой  UTI .imagegallery.

Пункты 1, 2 обязательные

  1. Документы Image Gallery в вашем приложении теперь должны сохраняться постоянно.
  2. Вы можете полностью убрать поддержку таблицы UITableView, добавленную на прошлой неделе.

Приложение Image Gallery — это как раз такое приложение, которое естественно хочется превратить в приложение, основанное на документах, то есть Document based app. Потому что с помощью Image Gallery вы можете создавать тематические живописные Галереи Изображений, и определенно вы захотите их сохранить.

Читать далее

Задание 5 Stanford CS 193P Fall 2017. Галерея изображений Image Gallery. Решение дополнительных пунктов.

Содержание

Текст Домашнего задания на английском языке доступен на  iTunes в пункте “Programming: Project 5: Image Gallery″. На русском языке вы можете скачать Задание 5 здесь:  Задание 5.pdf

Для решения Задания 5 необходимо ознакомиться с Лекцией 7, Лекцией 11Лекцией 12 и началом Лекции 13.

Логически выполнение обязательных пунктов Задания 5 распалось на две части: первая часть ( ей был посвящен пост «Задание 5 Stanford CS 193P Fall 2017. Галерея изображений Image Gallery. Решение обязательных пунктов. Часть 1) обеспечивает работу одной Галереи Изображений Image Gallery и использует исключительно коллекцию Collection View, а вторая часть ( ей был посвящен пост «Задание 5 Stanford CS 193P Fall 2017. Галерея изображений Image Gallery. Решение обязательных пунктов. Часть 2.») обеспечивает работу со списком имен Галерей Изображений с помощью таблицы Table View, которая взаимодействует с коллекцией изображений Collection View.

Этот пост мы посвятим оставшимся дополнительным пунктам (Extra Credit) Задания 5.

Мое решение обязательных и дополнительных пунктов Задания 5 находится на Github для iOS 11 и на Github для iOS 12 в папке ImageGallery_V. В разных папках размещен код для нескольких последовательных этапов выполнения Задания 5:

  1. ImageGalleryOnly — работает только коллекция изображений Сollection View
  2. ImageGalleryRequiedTable — работает только таблица имен Table View
  3. ImageGalleryRequiedTwoSeguesSplit View Controller с двумя Segues для разных ПРОТОТИПОВ
  4. ImageGalleryRequiedGenericSegueSplit View Controller с одним Segue и ручным «переездом»
  5. ImageGalleryRequiedNoSegueSplit View Controller без Segue для iPad (обязательные пункты в наиболее комфортном для пользователя исполнении)
  6. ImageGalleryRequiedNoSegueExtra — ОКОНЧАТЕЛЬНЫЙ ВАРИАНТ Задания 5 с обязательными и дополнительными пунктами.

Пункт 1 дополнительный (Extra Credit)

Позвольте пользователям перетаскивать Drag элементы коллекции Collection View в “мусорный бак” (возможно на навигационной панели вверху), что удалит этот URL из Галереи изображений (Image Gallery).

Идея того, как это можно сделать, заключается в следующем.

Читать далее

Задание 5 Stanford CS 193P Fall 2017. Галерея изображений Image Gallery. Решение обязательных пунктов. Часть 2.

Содержание

В Задании 5 вы должны освоить работу с Table View, Collection View, Scroll View и Text Fields, понять, как работает многопоточность (multithreading) и механизма Drag & Drop

Разработка Задания 5 начинается “с нуля”. Оно не имеет отношения к первым 4-м Заданиям этого семестра.

Текст Домашнего задания на английском языке доступен на  iTunes в пункте “Programming: Project 5: Image Gallery″. На русском языке вы можете скачать Задание 5 здесь: Задание 5.pdf.

Для решения Задания 5 необходимо ознакомиться с Лекцией 7, Лекцией 11Лекцией 12 и началом Лекции 13.

Центральной частью этого Задания 5 является коллекция изображений Collection View, которая моделирует Галерею Изображений Image Gallery. Необходимо обеспечить ее работоспособность, настроить ее параметры для отображения изображений в удобной и визуально привлекательной форме, подключить определенные жесты для операций над ее элементами, а также наделить ее механизмом Drag & Drop, который позволит добавлять изображения из других приложений, например, поисковой системы Google, и избавляться от ненужных элементов, кидая их в «Мусорный контейнер». В приложении предполагается создание целой серии таких тематических Галерей Изображений, каждой из которых будет дано имя, а список имен всех Галерей размещен в таблице Table View, которую тоже можно будет редактировать.

Логически выполнение обязательных пунктов Задания 5 распадается на две части: первая часть ( ей был посвящен пост «Задание 5 Stanford CS 193P Fall 2017. Галерея изображений Image Gallery. Решение обязательных пунктов. Часть 1.») будет обеспечивать работу одной Галереи Изображений Image Gallery и будет использовать исключительно коллекцию Collection View, а вторая часть будет обеспечивать работу со списком имен Галерей Изображений с помощью таблицы Table View, функционирование которой мы отработаем отдельно, а затем подстыкуем к ней коллекцию Collection View, уже настроенную под Галерею изображений Image Gallery.

Вторая часть будет представлена в этом посте.

Мое решение обязательных пунктов Задания 5 находится на Github для iOS 11 и на Github для iOS 12  в папке ImageGallery_V. Задание очень большое и сложное, поэтому я разместила код для нескольких последовательных этапов его выполнения, что позволит вам проверять ваш код на разных стадиях выполнения Задания 5:

  1. ImageGalleryOnly — работает только коллекция изображений Сollection View
  2. ImageGalleryRequiedTable — работает только таблица имен Table View
  3. ImageGalleryRequiedTwoSeguesSplit View Controller с двумя Segues для разных ПРОТОТИПОВ
  4. ImageGalleryRequiedGenericSegueSplit View Controller с одним Segue и ручным «переездом»
  5. ImageGalleryRequiedNoSegueSplit View Controller без Segue для iPad (наиболее комфортный для пользователя), это ОКОНЧАТЕЛЬНЫЙ ВАРИАНТ выполнения обязательных пунктов Задания 5.

Читать далее