If you’re an iOS developer, you’re probably familiar with the ReactiveX library and its implementation in Swift, RxSwift. RxSwift provides a powerful way to handle asynchronous events and data streams in a reactive, functional manner. However, with its vast array of operators and syntax, it can be daunting to remember everything. That’s where an RxSwift cheatsheet comes in handy.
Contents 非表示
Operators
map
: This operator applies a function to each element emitted by the source observable, producing a new observable with the transformed values.filter
: This operator filters the elements emitted by the source observable by applying a predicate function to each element, only emitting those that satisfy the condition.flatMap
: This operator applies a function that returns an observable to each element emitted by the source observable, flattening the resulting observables into a single stream of values.distinctUntilChanged
: This operator filters out consecutive duplicate values emitted by the source observable, only emitting those that are different from the previous value.debounce
: This operator waits for a specified amount of time of inactivity on the source observable before emitting the most recent value emitted by the source observable.throttle
: This operator emits the first value emitted by the source observable and then ignores subsequent values emitted within a specified time interval.startWith
: This operator emits a specified value as the first element of the resulting observable, followed by the elements emitted by the source observable.take
: This operator emits a specified number of elements from the beginning of the source observable, then completes.skip
: This operator ignores a specified number of elements from the beginning of the source observable, then emits the remaining elements.merge
: This operator combines multiple observables into a single observable that emits all of the elements from each observable, as they are emitted.
Examples
map
The map
operator transforms each element in a stream to a new element.
Observable.of(1, 2, 3, 4)
.map { $0 * 2 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
// Output:
// 2
// 4
// 6
// 8
In this example, we create an observable that emits the numbers 1 through 4. We then use the map
operator to multiply each number by 2, transforming the stream to emit 2, 4, 6, and 8.
filter
The filter
operator emits only the elements that pass a certain condition.
Observable.of(1, 2, 3, 4)
.filter { $0 % 2 == 0 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
// Output:
// 2
// 4
In this example, we create an observable that emits the numbers 1 through 4. We then use the filter
operator to only emit the even numbers, filtering out 1 and 3.
flatMap
The flatMap
operator transforms each element in a stream into a new stream, then merges them into a single stream.
let observable1 = Observable.of(1, 2)
let observable2 = Observable.of(3, 4)
observable1.flatMap { _ in observable2 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
// Output:
// 3
// 4
// 3
// 4
In this example, we create two observables that emit the numbers 1 through 2 and 3 through 4, respectively. We then use the flatMap
operator to transform each element in the first observable to emit the entire second observable. The resulting stream emits each number in the second observable twice.
distinctUntilChanged
The distinctUntilChanged
operator emits only elements that are distinct from the previous element.
Observable.of(1, 1, 2, 2, 3, 4, 4, 4, 5)
.distinctUntilChanged()
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
// Output:
// 1
// 2
// 3
// 4
// 5
In this example, we create an observable that emits several repeated numbers. We then use the distinctUntilChanged
operator to only emit each number once, excluding the duplicates.
debounce
The debounce
operator emits only the last element in a stream after a certain time interval has passed without any new elements being emitted.
let searchQuery = PublishSubject<String>()
searchQuery
.debounce(.milliseconds(500), scheduler: MainScheduler.instance)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
searchQuery.onNext("r")
searchQuery.onNext("rx")
searchQuery.onNext("rxs")
searchQuery.onNext("rxsw")
searchQuery.onNext("rxswi")
searchQuery.onNext("rxswif")
searchQuery.onNext("rxswift")
// Output:
// "rxswift"
In this example, we create a PublishSubject
that will emit search queries. We then use the debounce
operator to wait for 500 milliseconds of inactivity before emitting the last search query entered by the user. This is useful for search functionality where you don’t want to make a network request for every keystroke, but rather wait for the user to finish typing before making the request.
When the user enters a search query, we immediately emit it through the searchQuery subject. However, we don’t want to immediately perform a search, so we use the debounce
operator to wait for 500 milliseconds of inactivity before emitting the last search query entered by the user. In this way, we ensure that we only perform a search after the user has finished typing their query. Finally, we print out the last search query emitted by the searchQuery
observable, which in this case is “rxswift”.
throttle
The throttle
operator emits the first element in a stream and then ignores subsequent elements for a certain time interval.
let buttonTap = PublishSubject<Void>()
buttonTap
.throttle(.seconds(2), scheduler: MainScheduler.instance)
.subscribe(onNext: { print("Button tapped") })
.disposed(by: disposeBag)
buttonTap.onNext(())
// Wait 1 second
buttonTap.onNext(())
// Output:
// Button tapped
In this example, we create a PublishSubject
that will emit whenever a button is tapped. We then use the throttle
operator to only emit the first tap, ignoring any subsequent taps that occur within 2 seconds of the first one.
startWith
The startWith
operator emits a specified element before the observable emits any other elements.
Observable.of(1, 2, 3, 4)
.startWith(0)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
// Output:
// 0
// 1
// 2
// 3
// 4
In this example, we create an observable that emits the numbers 1 through 4. We then use the startWith
operator to emit 0 before emitting the rest of the numbers.
take
The take
operator emits only the first n elements in a stream.
Observable.of(1, 2, 3, 4)
.take(2)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
// Output:
// 1
// 2
In this example, we create an observable that emits the numbers 1 through 4. We then use the take
operator to only emit the first 2 numbers, ignoring the rest.
skip
The skip
operator ignores the first n elements in a stream and emits the rest.
Observable.of(1, 2, 3, 4)
.skip(2)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
// Output:
// 3
// 4
In this example, we create an observable that emits the numbers 1 through 4. We then use the skip
operator to ignore the first 2 numbers and emit the rest.
merge
The merge
operator merges multiple observables into a single observable.
let observable1 = Observable.of(1, 2)
let observable2 = Observable.of(3, 4)
Observable.merge(observable1, observable2)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
// Output:
// 1
// 2
// 3
// 4
In this example, we create two observables that emit the numbers 1 through 2 and 3 through 4, respectively. We then use the merge
operator to merge the two observables into a single observable that emits all of the numbers.
Conclusion
In conclusion, RxSwift provides a powerful and flexible way to work with asynchronous and event-driven programming in Swift. The numerous operators and features of RxSwift can be overwhelming at first, but by familiarizing yourself with the most commonly used operators, you can make the most of RxSwift in your projects.
In this cheatsheet, we have covered some of the most commonly used operators in RxSwift, including map
, flatMap
, filter
, scan
, throttle
, startWith
, take
, skip
, and merge
. With these operators, you can transform, filter, and combine streams of data to suit your needs.
Remember that RxSwift is not a one-size-fits-all solution, and it’s important to consider whether it’s the right tool for the job. But if you find yourself working with asynchronous data and events in Swift, RxSwift is definitely worth considering.