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")
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)
Skip()
先頭か指定された数まで、イベント発火をスキップする。
let disposeBag = DisposeBag()
// 1
Observable.of("A", "B", "C", "D", "E", "F")
// 2
.skip(3)
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
SkipWhile()
ある条件が成立するまで、イベントを通さない。一度通ったあとは、全部通す。
// 1
Observable.of(2, 2, 3, 4, 4)
// 2
.skipWhile { $0.isMultiple(of: 2) }
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
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")
take()
Skipオべレーターの逆、指定した数までイベントを発火、それ以降はイベントを止める。
let disposeBag = DisposeBag()
// 1
Observable.of(1, 2, 3, 4, 5, 6)
// 2
.take(3)
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
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)
takeUntil()
条件が満たされるまでイベントを発火。最期のイベントを発火するかどうか選択できる。
// 1
Observable.of(1, 2, 3, 4, 5)
// 2
.takeUntil(.exclusive) { $0.isMultiple(of: 4) }
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
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")
distinctUntilChanged()
エレメントが重複する場合、一度目のイベントのみを発火、それ以降はエレメントが変わるまでイベントを発火しない。
// 1
Observable.of("A", "A", "B", "B", "A")
// 2
.distinctUntilChanged()
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
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)
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)
参考文献
RxSwift: Reactive Programming with Swift
Filtering Operators Written by Scott Gardner
詳細が気になる方はこちらをご参照ください!
https://www.raywenderlich.com/13285844-rxswift-reactive-programming-with-swift-update-now-available











