Операторы позволяют удобно преобразовывать последовательность приходящих событий в RxSwift. Их можно разделить на несколько основных групп (назначение каждой из групп, думаю, говорит само за себя):
- Фильтрующие
- Трансформирующие
- Комбинирующие
Сегодня мы рассмотрим самые показательные примеры из каждой группы, полный список операторов и их возможности всегда можно найти в документации.
Для большинства примеров я буду использовать объект типа Observable
.
let elements = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let observable = Observable.from(elements)
Для демонстрации примеров в Playgrounds я реализовал вспомогательный метод, который создаёт подписку и выводит полученные значения в консоль.
func example<T>(of name: String, _ observable: T) where T: ObservableType, T.Element == Int {
var subscriptionResult = "--"
observable
.subscribe(
onNext: { value in
subscriptionResult += " \(value) --"
},
onCompleted: {
print("\(name) | \(subscriptionResult)>")
})
.disposed(by: disposeBag)
}
Теперь мы можем вывести последовательность, которая получится в результате, простой командой, например:
example(of: "elementAt",
observable.elementAt(1)
)
После выполнения этого кода у нас в консоли выведется результирующая последовательность (с названием, которое мы передали первым параметром):
elementAt | -- 1 —>
В примерах ниже, для краткости и читаемости, я не буду оборачивать код каждый раз в метод example
, но это подразумевается.
Фильтрующие операторы
Фильтрующие операторы отвечают за то, чтобы исключить некоторые элементы из последовательности.
elementAt
— оставляет только элемент указанного индекса и игнорирует все прочие элементы.
observable.elementAt(1)
Результат выполнения можно представить следующим образом (сверху оригинальная последовательность, снизу отфильтрованная):
Original | -- 0 -- 1 -- 2 -- 3 -- 4 -- 5 -- 6 -- 7 -- 8 -- 9 -- 10 -->
elementAt | -- 1 -->
filter
— работает, как и одноименный оператор в Swift. Например:
observable.filter { $0 % 2 == 0 }
Результат выполнения:
Original | -- 0 -- 1 -- 2 -- 3 -- 4 -- 5 -- 6 -- 7 -- 8 -- 9 -- 10 -->
filter | -- 0 -- 2 -- 4 -- 6 -- 8 -- 10 —>
skip
— позволяет пропустить заданное количество элементов последовательности. Можно реализовать более сложное поведение при помощи операторов skipWhile
и skipUntil
.
observable.skip(3)
Результат выполнения:
Original | -- 0 -- 1 -- 2 -- 3 -- 4 -- 5 -- 6 -- 7 -- 8 -- 9 -- 10 -->
skip | -- 3 -- 4 -- 5 -- 6 -- 7 -- 8 -- 9 -- 10 -->
take
— работает противоположно skip
, т.е. оставляет заданное количество элементов из последовательности. Есть варианты этого оператора takeWhile
и takeUntil
.
observable.take(2)
Результат выполнения:
Original | -- 0 -- 1 -- 2 -- 3 -- 4 -- 5 -- 6 -- 7 -- 8 -- 9 -- 10 -->
take | -- 0 -- 1 —>
distinctUntilChange
- игнорирует дублирующиеся элементы до тех пор пока, не придет элемент отличный от предыдущего.
let elementsToDistinct = [0, 1, 1, 1, 2, 2, 1, 1,]
let distinctObservable = Observable.from(elementsToDistinct)
distinctObservable.distinctUntilChanged()
В результате получим:
Original | -- 0 -- 1 -- 1 -- 1 -- 2 -- 2 -- 1 -- 1 -->
distinctUntil | -- 0 -- 1 -- 2 -- 1 -->
Трансформирующие операторы
Трансформирующие операторы помогают совершать действия над элементами последовательность.
Самый простой и понятный пример трансформирующего оператора - map
. Его принцип работы аналогичен одноименному оператору в Swift: он позволяет применить функцию к каждому из элементов последовательности.
observable.map { $0 * 10 }
Результат выполнения:
Original | -- 0 -- 1 -- 2 -- 3 -- 4 -- 5 -- 6 -- 7 -- 8 -- 9 -- 10 -->
map | -- 0 -- 10 -- 20 -- 30 -- 40 -- 50 -- 60 -- 70 -- 80 -- 90 -- 100 —>
reduce
- тоже работает как одноименный оператор в Swift: применяет функцию последовательно к каждому транслированному значению, а затем возвращает финальный результат.
observable.reduce(0, accumulator: +)
Результат выполнения:
Original | -- 0 -- 1 -- 2 -- 3 -- 4 -->
Original | -- 5 -- 6 -- 7 -- 8 -- 9 -->
reduce | -- 55 —>
Комбинирующие операторы
Комбинирующие операторы помогают каким-либо образом объединить вместе события приходящие из нескольких последовательностей.
В своих экспериментах ниже я буду использовать 2 последовательности чисел, на основе которых создам 2 обозреваемых объекта.
let elements1 = [0, 1, 2, 3, 4]
let elements2 = [5, 6, 7, 8, 9]
let observable1 = Observable.from(elements1)
let observable2 = Observable.from(elements2)
merge
- объединяет элементы нескольких последовательностей.
Observable.merge(observable1, observable2)
Результат выполнения:
Original | -- 0 -- 1 -- 2 -- 3 -- 4 -->
Original | -- 5 -- 6 -- 7 -- 8 -- 9 -->
merge | -- 0 -- 5 -- 1 -- 6 -- 2 -- 7 -- 3 -- 8 -- 4 -- 9 —>
concat
- склеивает заданные последовательности в одну, при условии, что они завершились без ошибок.
Observable.concat(observable1, observable2)
Результат выполнения:
Original | -- 0 -- 1 -- 2 -- 3 -- 4 -->
Original | -- 5 -- 6 -- 7 -- 8 -- 9 -->
concat | -- 0 -- 1 -- 2 -- 3 -- 4 -- 5 -- 6 -- 7 -- 8 -- 9 -->
combineLatest
- объединяет 2 последовательности, применяя функцию для преобразования. В примере ниже мы перемножаем элементы двух последовательностей событий.
Observable.combineLatest(observable1, observable2, resultSelector: { $0 * $1 })
Результат выполнения:
Original | -- 0 -- 1 -- 2 -- 3 -- 4 -->
Original | -- 5 -- 6 -- 7 -- 8 -- 9 -->
combineLatest | -- 0 -- 5 -- 6 -- 12 -- 14 -- 21 -- 24 -- 32 -- 36 -->
Сегодня мы рассмотрели только некоторые примеры операторов, оставив за кадром ещё большое количество, потому как я не ставил целью переводить документацию, а лишь продемонстрировал общий принцип. Настоятельно рекомендую ознакомиться со всеми группами и возможностями Rx-операторов по ссылке в начале этой статьи.