【Xcode/Swift】RxSwift cheatsheet

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.

Operators

  1. map: This operator applies a function to each element emitted by the source observable, producing a new observable with the transformed values.
  2. 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.
  3. 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.
  4. distinctUntilChanged: This operator filters out consecutive duplicate values emitted by the source observable, only emitting those that are different from the previous value.
  5. 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.
  6. throttle: This operator emits the first value emitted by the source observable and then ignores subsequent values emitted within a specified time interval.
  7. startWith: This operator emits a specified value as the first element of the resulting observable, followed by the elements emitted by the source observable.
  8. take: This operator emits a specified number of elements from the beginning of the source observable, then completes.
  9. skip: This operator ignores a specified number of elements from the beginning of the source observable, then emits the remaining elements.
  10. 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.