Использование потребителей и операторов непосредственно в вашем коде 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 для уведомления о подписке.

Для дальнейшего чтения по теме рекомендую эту статью Джо Хека. Также есть более длинная статья Тибора Бедеча и еще одна другого писателя-медиума Ахмеда Насера.

Сохраняйте спокойствие, продолжайте кодировать.