Combining Operators
RxSwiftでコードを書く必要があり、学習中です。
参考文献を元に学んだ内容をすぐ振り返れるようにまとめていきます。
今回はCombining Operatorsについてまとめました。
完全に自分の解釈でコメントを載せていますが、解釈に誤りがありましたら、コメント欄より教えてください。
startWith()
example(of: "startWith") {
// 1
let numbers = Observable.of(2, 3, 4)
// 2
let observable = numbers.startWith(1)
_ = observable.subscribe(onNext: { value in
print(value)
})
}
コンパイル結果
Observable.concat
同じ型同士の時のみ、Concatできる!
example(of: "Observable.concat") {
// 1
let first = Observable.of(1, 2, 3)
let second = Observable.of(4, 5, 6)
// 2
let observable = Observable.concat([first, second])
observable.subscribe(onNext: { value in
print(value)
})
}
コンパイル結果
concat
example(of: "concat") {
let germanCities = Observable.of("Berlin", "Münich", "Frankfurt")
let spanishCities = Observable.of("Madrid", "Barcelona", "Valencia")
let observable = germanCities.concat(spanishCities)
_ = observable.subscribe(onNext: { value in
print(value)
})
}
コンパイル結果
concatMap
example(of: "concatMap") {
// 1
let sequences = [
"German cities": Observable.of("Berlin", "Münich", "Frankfurt"),
"Spanish cities": Observable.of("Madrid", "Barcelona", "Valencia")
]
// 2
let observable = Observable.of("German cities", "Spanish cities")
.concatMap { country in sequences[country] ?? .empty() }
// 3
_ = observable.subscribe(onNext: { string in
print(string)
})
}
コンパイル結果
mege
maxConcurrentを使うことで、同時にObserveするSequenceの上限を設定できる。
example(of: "merge") {
// 1
let left = PublishSubject<String>()
let right = PublishSubject<String>()
// 2
let source = Observable.of(left.asObservable(), right.asObservable())
// 3
let observable = source.merge(maxConcurrent: 2)
_ = observable.subscribe(onNext: { value in
print(value)
})
// 4
var leftValues = ["Berlin", "Munich", "Frankfurt"]
var rightValues = ["Madrid", "Barcelona", "Valencia"]
repeat {
switch Bool.random() {
case true where !leftValues.isEmpty:
left.onNext("Left: " + leftValues.removeFirst())
case false where !rightValues.isEmpty:
right.onNext("Right: " + rightValues.removeFirst())
default:
break
}
} while !leftValues.isEmpty || !rightValues.isEmpty
// 5
left.onCompleted()
right.onCompleted()
}
コンパイル結果
combineLatest
全てのObservableから値が発信されるまで、何もしない。異なる方のSequenceをまとめて、最新の値を取り出す。
example(of: "combineLatest") {
let left = PublishSubject<String>()
let right = PublishSubject<String>()
// 1
// let observable = Observable.combineLatest(left, right) {
// lastLeft, lastRight in
// "\(lastLeft) \(lastRight)"
// }
// 1 combineLatestでタプルにして、filterをかける方法がよく使われる。
// let observable = Observable
// .combineLatest(left, right) { ($0, $1) }
// .filter { !$0.0.isEmpty }
// 1: Stringが確か受付内ため、余り使われない方法
let observable = Observable.combineLatest([left, right]) {
strings in strings.joined(separator: " ")
}
_ = observable.subscribe(onNext: { value in
print(value)
})
// 2
print("> Sending a value to Left")
left.onNext("Hello,")
print("> Sending a value to Right")
right.onNext("world")
print("> Sending another value to Right")
right.onNext("Swift")
print("> Sending another value to Left")
left.onNext("Have a good day,")
left.onCompleted()
right.onCompleted()
}
コンパイル結果
combine user choice and value
ユーザーの設定が変更した時に、表示値を変える
example(of: "combine user choice and value") {
let choice: Observable<DateFormatter.Style> = Observable.of(.short, .long)
let dates = Observable.of(Date())
let observable = Observable.combineLatest(choice, dates) {
format, when -> String in
let formatter = DateFormatter()
formatter.dateStyle = format
return formatter.string(from: when)
}
_ = observable.subscribe(onNext: { value in
print(value)
})
}
コンパイル結果
zip
indexed sequencing: ペアが成立しなくなったら、zipは値を発しなくなるが、observableがCompleteするまで処理が終わらないため、observableが完了していることを確認すること。
example(of: "zip") {
enum Weather {
case cloudy
case sunny
}
let left: Observable<Weather> = Observable.of(.sunny, .cloudy, .cloudy, .sunny, .cloudy)
let right = Observable.of("Lisbon", "Copenhagen", "London", "Madrid", "Vienna")
let observable = Observable.zip(left, right) { weather, city in
return "It's \(weather) in \(city)"
}
_ = observable.subscribe(onNext: { value in
print(value)
})
}
コンパイル結果
withLatestFrom
example(of: "withLatestFrom") {
// 1
let button = PublishSubject<Void>()
let textField = PublishSubject<String>()
// 2
//the trigger observableが撮りガー
let observable = textField.sample(button)
//data Observableがトリガー
// let observable = button.withLatestFrom(textField)
_ = observable.subscribe(onNext: { value in
print(value)
})
// 3
textField.onNext("Par")
textField.onNext("Pari")
textField.onNext("Paris")
button.onNext(())
button.onNext(())
}
コンパイル結果
amb
二つのObservableのどちらをつかうかAmbiguousな場合。 使い所:connecting to redundant servers and sticking with the one that responds first.
example(of: "amb") {
let left = PublishSubject<String>()
let right = PublishSubject<String>()
// 1
let observable = left.amb(right)
_ = observable.subscribe(onNext: { value in
print(value)
})
// 2
left.onNext("Lisbon")
right.onNext("Copenhagen")
left.onNext("London")
left.onNext("Madrid")
right.onNext("Vienna")
left.onCompleted()
right.onCompleted()
}
コンパイル結果
switchLatest
example(of: "switchLatest") {
// 1
let one = PublishSubject<String>()
let two = PublishSubject<String>()
let three = PublishSubject<String>()
let source = PublishSubject<Observable<String>>()
// 2
let observable = source.switchLatest()
let disposable = observable.subscribe(onNext: { value in
print(value)
})
// 3
source.onNext(one)
one.onNext("Some text from sequence one")
two.onNext("Some text from sequence two")
source.onNext(two)
two.onNext("More text from sequence two")
one.onNext("and also from sequence one")
source.onNext(three)
two.onNext("Why don't you see me?")
one.onNext("I'm alone, help me")
three.onNext("Hey it's three. I win.")
source.onNext(one)
one.onNext("Nope. It's me, one!")
disposable.dispose()
}
コンパイル結果
reduce
注意:sequencesが完了しないと、Summaryがemitされない。
example(of: "reduce") {
let source = Observable.of(1, 3, 5, 7, 9)
// 1
// let observable = source.reduce(0, accumulator: +)
let observable = source.reduce(0){summary, newValue in
return summary + newValue
}
_ = observable.subscribe(onNext: { value in
print(value)
})
}
コンパイル結果
scan
累計、統計、状態をコンピュートする際に使える。
値が変わると毎回、Observableから値がEmitされる。
example(of: "scan") {
let source = Observable.of(1, 3, 5, 7, 9)
let observable = source.scan(0, accumulator: +)
_ = observable.subscribe(onNext: { value in
print(value)
})
}
コンパイル結果
練習
example(of: "Challeng1") {
let source = Observable.of(1, 3, 5, 7, 9)
let scanedObservable = source.scan(0, accumulator: +)
let observable = Observable.zip(source, scanedObservable){current, total -> String in
return "Total:\(String(total)), Current:\(String(current)))"
}
_ = observable.subscribe(onNext: { value in
print(value)
})
}
コンパイル結果
練習
acc(current, accumuratedValue)となるから、acc.1 + currentとしている。
//acc(current, accumuratedValue)となるから、acc.1 + currentとしている。
example(of: "Challeng2") {
let source = Observable.of(1, 3, 5, 7, 9)
let observable = source.scan((0, 0)) { acc, current in
print("acc\(acc)")
print("current\(current)")
return (current, acc.1 + current)
}
_ = observable.subscribe(onNext: { tuple in
print("Value = \(tuple.0) Running total = \(tuple.1)")
})
}
コンパイル結果
参考文献
1.Combining Operators Written by Florent Pillet
Chapter9 Transforming Operators Written by Scott Gardner
詳細が気になる方はこちらをご参照ください!
https://www.raywenderlich.com/13285844-rxswift-reactive-programming-with-swift-update-now-available