RxSwift Filtering Operators

31 分钟读完

Ignoring operators

ignoreElements

使用 ignoreElements 操作符可以忽略所有的 .next 事件,而让终止事件通过,比如 .error.completed

看一个例子

example(of: "ignoreElements") {
  // 1
  let strikes = PublishSubject<String>()

  let disposeBag = DisposeBag()

  // 2
  strikes
    .ignoreElements()
    .subscribe { _ in
      print("You're out!")
    }
    .disposed(by: disposeBag)
  
  strikes.onNext("X")
	strikes.onNext("X")
	strikes.onNext("X")
  strikes.onCompleted()
}

输出
--- Example of: ignoreElements ---
You're out!

上面的例子可以看出,所有的 next 事件都被忽略了,只剩 completed 事件通过,所以只打印了一次

ignoreElements 操作符会返回一个 Completable 序列

elementAt

在只希望处理序列中的第 n 个事件的时候可以使用 elementAt 操作符,它会只通过指定 index 的事件,忽略其它的事件

example(of: "elementAt") {

  // 1
  let strikes = PublishSubject<String>()

  let disposeBag = DisposeBag()

  //  2
  strikes
    .elementAt(2)
    .subscribe(onNext: { _ in
      print("You're out!")
    })
    .disposed(by: disposeBag)
  
  strikes.onNext("X")
	strikes.onNext("X")
	strikes.onNext("X")
}

输出
--- Example of: elementAt ---
You're out!

在发出指定 index 的事件之后,订阅将会终止

filter

filter 操作符和 Swift 标准库中的 filter 方法基本相同,根据 filter block 的返回值做筛选,只允许通过返回值为 true 的元素

example(of: "filter") {
  let disposeBag = DisposeBag()

  // 1
  Observable.of(1, 2, 3, 4, 5, 6)
    // 2
    .filter { $0 % 2 == 0 }
    // 3
    .subscribe(onNext: {
      print($0)
    })
    .disposed(by: disposeBag)
}

输出
--- Example of: filter ---
2
4
6

Skipping operators

skip

skip 操作符可以跳过前 n 个事件,比如 skip(2) 就是跳过前两个事件

example(of: "skip") {
  let disposeBag = DisposeBag()

  // 1
  Observable.of("A", "B", "C", "D", "E", "F")
    // 2
    .skip(3)
    .subscribe(onNext: {
      print($0)
    })
    .disposed(by: disposeBag)
}

输出
--- Example of: skip ---
D
E
F

skipWhile

skipWhile 与 filter 类似的地方是接收一个筛选条件

不同的是 skipWhile 在通过第一个元素之后便不再筛选,会让之后的元素都通过

skipWhile 的筛选条件为 true 时会跳过事件,为 false 时会让事件通过

example(of: "skipWhile") {
  let disposeBag = DisposeBag()

  // 1
  Observable.of(2, 2, 3, 4, 4)
    // 2
    .skipWhile { $0 % 2 == 0 }
    .subscribe(onNext: {
      print($0)
    })
    .disposed(by: disposeBag)
}

输出
--- Example of: skipWhile ---
3
4
4

skipUntil

之前的筛选操作符都是基于静态的条件,skipUntil 操作符及后面的一些操作符可以把其它的序列作为筛选条件

skipUntil 接收一个 Observable 的 trigger 参数,在 trigger 发出一个 .next 事件之前,skipUntil 会把所有的事件跳过

example(of: "skipUntil") {
  let disposeBag = DisposeBag()

  // 1
  let subject = PublishSubject<String>()
  let trigger = PublishSubject<String>()

  // 2
  subject
    .skipUntil(trigger)
    .subscribe(onNext: {
      print($0)
    })
    .disposed(by: disposeBag)
  
  subject.onNext("A")
	subject.onNext("B")
  trigger.onNext("X")
  subject.onNext("C")
}

输出
--- Example of: skipUntil ---
C

Taking operators

Taking 是和 skipping 相反的操作符

take

take 操作符让前 n 个操作符通过

example(of: "take") {
  let disposeBag = DisposeBag()

  // 1
  Observable.of(1, 2, 3, 4, 5, 6)
    // 2
    .take(3)
    .subscribe(onNext: {
      print($0)
    })
    .disposed(by: disposeBag)
}

输出
--- Example of: take ---
1
2
3

takeWhile

takeWhile 和 skipWhile 相似,但是是通过而不是跳过

takeWhile 在遇到以一个不通过的事件的时候后面的元素都会跳过

example(of: "takeWhile") {
  let disposeBag = DisposeBag()

  // 1
  Observable.of(2, 2, 4, 4, 6, 6)
    // 2
    .enumerated()
    // 3
    .takeWhile { index, integer in
      // 4
      integer % 2 == 0 && index < 3
    }
    // 5
    .map { $0.element }
    // 6
    .subscribe(onNext: {
      print($0)
    })
    .disposed(by: disposeBag)
}

输出
--- Example of: takeWhile ---
2
2
4

takeUntil

类似于 skipUntil 接收一个 trigger 参数,在 trigger 发出 next 之前会一直让事件通过,跳过 trigger 发出 next 事件之后的事件

example(of: "takeUntil") {
  let disposeBag = DisposeBag()

  // 1
  let subject = PublishSubject<String>()
  let trigger = PublishSubject<String>()

  // 2
  subject
    .takeUntil(trigger)
    .subscribe(onNext: {
      print($0)
    })
    .disposed(by: disposeBag)

  // 3
  subject.onNext("1")
  subject.onNext("2")
  
  // trigger
  trigger.onNext("X")
	subject.onNext("3")
}

输出
--- Example of: takeUntil ---
1
2

takeUntil 的另一个用途是处理订阅的生命周期,如果没有把订阅放到一个 bag 中,可以使用这种方式,但是一般还是使用 DisposeBag

_ = someObservable
    .takeUntil(self.rx.deallocated)
    .subscribe(onNext: {
        print($0)
    })

Distinct operators

Distinct 操作符可以避免相邻的相同的元素

example(of: "distinctUntilChanged") {
  let disposeBag = DisposeBag()

  // 1
  Observable.of("A", "A", "B", "B", "A")
    // 2
    .distinctUntilChanged()
    .subscribe(onNext: {
      print($0)
    })
    .disposed(by: disposeBag)
}

输出
--- Example of: distinctUntilChanged ---
A
B
A

上面例子的元素类型是 String,本身是遵守并实现了 Equatable 协议的类型,所以可以比较,distinctUntilChanged 也可以接受自定义的比较

distinctUntilChanged

example(of: "distinctUntilChanged(_:)") {
  let disposeBag = DisposeBag()
  
  // 1
  let formatter = NumberFormatter()
  formatter.numberStyle = .spellOut

  // 2
  Observable<NSNumber>.of(10, 110, 20, 200, 210, 310)
    // 3
    .distinctUntilChanged { a, b in
      // 4
      guard let aWords = formatter.string(from: a)?.components(separatedBy: " "),
      let bWords = formatter.string(from: b)?.components(separatedBy: " ")
        else {
          return false
      }

      var containsMatch = false

      // 5
      for aWord in aWords where bWords.contains(aWord) {
        containsMatch = true
        break
      }

      return containsMatch
    }
    // 4
    .subscribe(onNext: {
      print($0)
    })
    .disposed(by: disposeBag)
}

输出
--- Example of: distinctUntilChanged(_:) ---
10
20
200

留下评论