Сравнение открытого фреймворка RxSwift и нативного Combine

Прежде всего, мы должны начать с объяснения того, что такое реактивное программирование. Это первый абзац определения в Википедии:

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

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

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

В Swift два основных способа выполнения реактивного программирования — это фреймворки Combine и RxSwift.

Презентация комбината

Apple широко представила SwiftUI во время WWDC 2019, но они почти не сказали, что существует целая структура, которая его поддерживает: Combine. Это огромная новая структура, которая была слишком технической, чтобы попасть в заголовок, но она знаменует собой большое изменение в философии Apple, переход от декларативного к функционально-реактивному подходу. Вы можете использовать его, начиная с iOS 13, и, хотя он очень тесно связан со SwiftUI, вы все равно можете связать его с UIKit.

Некоторые типы Foundation раскрывают свои функциональные возможности через издателей, включая Timer, NotificationCenter и URLSession. Combine также предоставляет встроенный издатель для любого свойства, совместимого с наблюдением за ключом и значением.

Не стесняйтесь проверять Документацию Apple о Combine для получения дополнительной информации.

Презентация RxSwift

RxSwift — это фреймворк с открытым исходным кодом. Вы можете использовать его, начиная с iOS 8. Это большое преимущество, так как вы можете безопасно начать интегрировать его в свой проект сейчас, в то время как вы можете подождать год или два, пока Combine будет поддерживать больше версий iOS.

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

Давайте сравним!

Об эмиттерах

Объединить: Publisher – это протокол, определяющий требования к типу, чтобы он мог передавать последовательность значений во времени одному или нескольким подписчикам. Это похоже на то, что делает NotificationCenter, за исключением того, что это, конечно, сделано лучше и читабельнее. Вы можете создать свой собственный, но Apple также предоставляет целый набор готовых издателей в своем enum.

let publisher = NotificationCenter.default
               .publisher(for: NSControl.textDidChangeNotification,
                object: filterField)

RxSwift: они называются Observable. Это класс, который передает потоки (на самом деле не испускает) Event, которые затем принимаются Observers. Подробнее об этом позже.

let name: String = "Peter"
let observable = Observable<String>.just(name)

О приемниках

Объединить: Subscriber – это протокол, определяющий требования к типу, чтобы он мог получать входные данные от Publisher.

let subscriber = NotificationCenter.default
                .publisher(for: NSControl.textDidChangeNotification,
                 object: filterField)
                .sink(receiveCompletion: { print ($0) },
                 receiveValue: { print ($0) })

RxSwift: Observer напрямую подписывается на Observable. В отличие от NotificationCenter, где разработчики обычно используют только одиночный экземпляр .default, каждый наблюдаемый объект в Rx отличается. Кроме того, очень важно знать, что наблюдаемый объект не будет транслировать события или выполнять какую-либо работу, пока у него не появится подписчик.

let name: String = "Peter"
let observable = Observable<String>.just(name)
observable.subscribe { event in   
    print(event)
}

В целом, у вас много общих операторов с более или менее одинаковыми именами. Шай Мишали сделал эту очень удобную таблицу вам в помощь.

Обратное давление

Комбинируйте поддержку противодавления, но это не относится к RxSwift. В ReactiveX нетрудно попасть в ситуацию, когда Observable передает элементы быстрее, чем оператор или наблюдатель может их использовать. Вы по-прежнему можете контролировать это с помощью холодных наблюдаемых, которые передают последовательность, когда ее наблюдатель считает это удобным, и с любой скоростью, которую желает наблюдатель, не нарушая целостность последовательности.

Тип ошибки

Для Combine требуется определенный тип ошибки, в то время как RxSwift работает с простым типом Error. Со стороны Альянса это может показаться более сложной задачей, но я думаю, что это к лучшему. Управление ошибками имеет решающее значение, и «принуждение» к использованию вашего пользовательского типа Error приведет к улучшению журналов ошибок.

Управление памятью

В RxSwift есть очень удобная система Dispose Bag. Все подписки на наблюдаемые объекты хранятся в одном уникальном объекте, что позволяет нам более эффективно управлять жизненным циклом этих подписок. При этом подписки также работают с ARC. Подписка всегда освобождается, когда она завершена или завершена из-за ошибки.

let disposeBag = DisposeBag()
let name: String = "Peter"
let observable = Observable<String>.just(name)
observable.subscribe { event in   
    print(event)
}.addDisposableTo(disposeBag)

Для объединения это называется Cancellable. Все подписки управляются отдельно. Это немного больше усилий, но для получения большего контроля над нашим кодом и, возможно, улучшения производительности, поскольку под капотом DisposeBag много операций.

private var cancellable: AnyCancellable?
self.cancellable = subject
                  .sink { value in       
                      print(value)
                   }

Спектакли

Apple разработала Combine с учетом аспекта производительности. Цитируя инженера Apple: «Модели памяти RxSwift и Combine очень разные. Комбайн действительно создан для производительности». Он почти удваивает характеристики RxSwift, что позволяет Apple интегрировать Combine в высокопроизводительные требовательные платформы, такие как RealityKit.

Заключение

У вас есть веские аргументы с обеих сторон, чтобы использовать тот или иной фреймворк. В целом, используйте Combine, если вы хотите использовать что-то, изначально интегрированное в iOS, и если вам не нужно поддерживать версии iOS до iOS 13. Это также приведет к увеличению производительности.

RxSwift, с другой стороны, охватывает более широкий спектр версий iOS, а также имеет более широкое сообщество и больше руководств/примеров/контента.

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