Использование потребителей и операторов непосредственно в вашем коде SwiftUI
Когда Apple запустила SwiftUI, они также втиснули вторую структуру, которая не привлекла столько внимания: Combine, который Apple описывает как унифицированный декларативный API для обработки значений с течением времени.
С учетом сказанного, декларативное кодирование уже некоторое время проникает в Swift. Прекрасным примером этого была презентация в 2018 году, которая остается одной из лучших универсальных презентаций WWDC за последние годы. Во время этой презентации Дэйв Абрахамс рассказывает нам об использовании алгоритмов.
Но подождите, это ведь не презентация о реактивном кодировании? Нет, это презентация об использовании правильных алгоритмов. В этом примере цель Дейва - отсортировать массив фигур. Он выполняет шаги, которые он предпринял, чтобы исправить проблемы с кодом. Исправления, которые в конечном итоге привели его к использованию реактивного кодирования с конструкциями, подобными тем, которые мы рассмотрим сегодня.
Объединить фреймворк
Давайте сосредоточимся на Combine. Он содержит издателей, подписчиков и операторов. Издатели отправляют данные, подписчики потребляют данные, а операторы являются посредниками. Хотя вы можете интегрировать их в SwiftUI через наблюдаемые и опубликованные объекты, вы также можете использовать функцию, называемую субъектами.
Субъекты важны в общей картине, потому что они публикуют данные, с которыми оператор может работать и в конечном итоге передают подписчику. В структуре Combine у вас есть два типа предметов:
PassthroughSubject
- пустой канал, по которому можно отправлять данные.CurrentValueSubject
- то же самое со значением по умолчанию.
Вы фиксируете данные, отправленные субъектами в SwiftUI, используя .onreceive
модификаторы представления, помимо которых вы можете использовать десятки операторов для их обработки перед передачей подписчику. Если у вас есть системный опыт, эта идея может показаться вам знакомой. В системном программировании вы используете вертикальную черту для постоянной передачи данных от одной утилиты к другой. Фреймворк Combine использует тот же принцип.
SE написали книги по использованию новой структуры. Здесь есть что переварить - слишком много для одной статьи, чтобы отдать должное - так что вот вам вкус того, что нужно сделать с дюжиной операций, подробно описанных в коде. Я поделился своим исследованием в конце, если вы хотите узнать больше сейчас. Если вы можете подождать, я планирую опубликовать еще несколько статей на эту тему в будущем.
Давайте погрузимся.
Показанный здесь оператор "sink”
использует данные и любые ошибки. При этом я распечатываю собранные данные (в данном случае “foobar”
):
Оператор "last”
читает наш список планет и возвращает последнюю отправленную. В этом случае он вернет “mercury”
:
Оператор “collect”
принимает данные от издателя, пока не получит указанный здесь номер (4
). Затем он передает его подписчику. В этом случае подписчик получает (0,1,2,3
), затем (4,5,6,7
) и, наконец, (8
). Это один из нескольких вариантов для данного оператора.
Вы наверняка видели “map”
раньше. Это преобразует тип опубликованных данных в новый указанный тип. Это важно, потому что типы данных и ошибок должны соответствовать издателям и подписчикам.
Оператор “scan”
принимает данные и, в нашем случае, складывает два последних полученных, прежде чем передать их подписчику. В результате получается последовательность 0 1 3 6 10 15 21 28
. Проходя через нее, вы получаете 0, 0
+ 1, 1
+ 2, 3
+ 3, 6
+ 4
и т. Д.
Оператор “output”
возвращает элемент в позиции, указанной в коде. В этом случае получаем “2416”
:
Оператор “reduce”
возвращает одну строку (в данном случае “abcdef”
). По сути, он берет все данные и возвращает их как единое целое:
Оператор “first”
очень похож на своего кузена, которого я уже упоминал, “last”
. Он вернет первый элемент, отправленный в потоке, и отбросит остальные. В этом случае получаем “mars”
:
Оператор “event”
немного необычен тем, что мы игнорируем данные здесь и просто уведомляем подписчика, когда они замолкают.
Оператор “compact”
будет проверять входящие данные (здесь мы ищем целые числа) и передавать только те, которые прошли проверку, отбрасывая остальные. В этом случае получаем [1,2,4,8]
:
Оператор removeDuplicates()
в основном удаляет смежные дубликаты, отправленные издателем. В этом случае мы получаем 1
, 2
, 3
, 4
, 8
, 9
и 10
. Если вы отправляете то же значение, но в другом порядке (например, если вы отправляете 1
между 3
и 4
), значение передается.
Обратите внимание, что этот оператор выглядит очень полезным для тех, кто использует объекты, которые иногда загадочным образом срабатывают несколько раз.
Последний оператор, который я здесь упомяну, “filter”
, очень полезен. В этом примере я ищу планеты, содержащие букву “a”
. Итак, мы получаем результат “Earth”
, “Mars”
, “Saturn”
и “Uranus”
:
На этом я подошел к концу этой довольно длинной статьи. Я уверен, что здесь вы видите закономерность. Я использовал sink
почти во всех примерах для использования данных и store
для уведомления о подписке.
Для дальнейшего чтения по теме рекомендую эту статью Джо Хека. Также есть более длинная статья Тибора Бедеча и еще одна другого писателя-медиума Ахмеда Насера.
Сохраняйте спокойствие, продолжайте кодировать.