1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

RxSwift FilterOperators チートシート

Last updated at Posted at 2020-11-24

FilterOperators

RxSwiftでコードを書く必要があり、学習中です。
参考文献を元に学んだ内容をすぐ振り返れるようにまとめていきます。
今回はFilter Operatersについてまとめました。
完全に自分の解釈でコメントを載せていますが、解釈に誤りがありましたら、コメント欄より教えてください。

elementAt()

指定したインデックスの場合のみ、インベントは発火

import Foundation
import RxSwift
  // 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")

コンパイル結果
Screen Shot 2020-11-23 at 12.26.48 AM.png

filter()

この場合、2で割り切れる値のみ表示する。条件に当てはまる場合のみ、イベントを発火。

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

コンパイル結果
Screen Shot 2020-11-23 at 12.26.21 AM.png

Skip()

先頭か指定された数まで、イベント発火をスキップする。

  let disposeBag = DisposeBag()

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

コンパイル結果
Screen Shot 2020-11-23 at 12.25.57 AM.png

SkipWhile()

ある条件が成立するまで、イベントを通さない。一度通ったあとは、全部通す。

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

コンパイル結果
Screen Shot 2020-11-23 at 12.25.17 AM.png

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")
    subject.onNext("D")

コンパイル結果
Screen Shot 2020-11-23 at 12.24.51 AM.png

take()

Skipオべレーターの逆、指定した数までイベントを発火、それ以降はイベントを止める。

  let disposeBag = DisposeBag()

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

コンパイル結果
Screen Shot 2020-11-23 at 12.24.20 AM.png

takeWhile()

条件が満たされる間は、イベントを発火

  let disposeBag = DisposeBag()

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

コンパイル結果
Screen Shot 2020-11-23 at 12.23.39 AM.png

takeUntil()

条件が満たされるまでイベントを発火。最期のイベントを発火するかどうか選択できる。

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

コンパイル結果
Screen Shot 2020-11-23 at 12.23.05 AM.png

takeUntil() Trigger

トリガーが軌道するまで、イベントを発火。それ以降は発火しない。

  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.onNext("X")
  subject.onNext("3")

コンパイル結果
Screen Shot 2020-11-23 at 12.21.41 AM.png

distinctUntilChanged()

エレメントが重複する場合、一度目のイベントのみを発火、それ以降はエレメントが変わるまでイベントを発火しない。

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

コンパイル結果
Screen Shot 2020-11-23 at 12.20.28 AM.png

distinctUntilChanged() 条件付き

後の数字の文字列に同じ要素が含まれないか確認、含まれる場合はスキップ、含まれない場合はイベントを発火!


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

  let disposeBag = DisposeBag()
  
  // 1
  let formatter = NumberFormatter()
  formatter.numberStyle = .spellOut

  // 2: フォーマッターで変換しなくていいように、はじめからNSNumberに!!
  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) {
        print(aWord)
        containsMatch = true
        break
      }

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

コンパイル結果
Screen Shot 2020-11-23 at 12.19.58 AM.png

Filter応用

import Foundation
import RxSwift

  let disposeBag = DisposeBag()
  
  let contacts = [
    "603-555-1212": "Florent",
    "212-555-1212": "Shai",
    "408-555-1212": "Marin",
    "617-555-1212": "Scott"
  ]
  
  func phoneNumber(from inputs: [Int]) -> String {
    var phone = inputs.map(String.init).joined()
    
    phone.insert("-", at: phone.index(
      phone.startIndex,
      offsetBy: 3)
    )
    
    phone.insert("-", at: phone.index(
      phone.startIndex,
      offsetBy: 7)
    )
    
    return phone
  }
  
  let input = PublishSubject<Int>()
  
  input
    .skipWhile {return $0 == 0}
    .filter {return  $0 < 10 }
    .take(10)
    .toArray()
    .subscribe(onSuccess: {
      let phone = phoneNumber(from: $0)
      if let contact = contacts[phone] {
        print("Dialing \(contact) (\(phone))...")
      } else {
        print("Contact not found")
      }
    })
    .disposed(by: disposeBag)
  
    //0 is rejected
  input.onNext(0)
    //Only figure less than 10 can be passed 
  input.onNext(603)
  
  input.onNext(6)
  input.onNext(0)
  input.onNext(3)
  
  "5551212".forEach {
    if let number = (Int("\($0)")) {
      input.onNext(number)
    }
  }
  
  input.onNext(9)

コンパイル結果
Screen Shot 2020-11-23 at 1.16.36 PM.png

参考文献

RxSwift: Reactive Programming with Swift
Filtering Operators Written by Scott Gardner
詳細が気になる方はこちらをご参照ください!
https://www.raywenderlich.com/13285844-rxswift-reactive-programming-with-swift-update-now-available

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?