๐Ÿ“ RxSwift | Operator

Thanks to @fimuxd ๐Ÿ–ค

https://github.com/ReactiveX/RxSwift
https://github.com/fimuxd/RxSwift


Section II:
Operators and Best Practices

Filtering Operators

Swift์˜ filter ์™€ ๋น„์Šท.
.next ์ด๋ฒคํŠธ๋ฅผ ํ†ตํ•ด ๋ฐ›์•„์˜ค๋Š” ๊ฐ’์„ ์„ ํƒ์ ์œผ๋กœ ์ทจํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฒƒ

Ignoring operators
1. .ignoreElements()
2. .elementAt
3. .filter

Skipping Operators
1. .skip
2. .skipWhile
3. .skipUntil

Taking Operators
1. .take
2. .takeWhile
3. .enumerated
4. .takeUntil

Distinct Operators
1. .distinctUntilChanged
2. .distinctUntilChanged(_:)



Ignoring operators

1. .ignoreElements()
.next ์ด๋ฒคํŠธ๋Š” ๋ฌด์‹œ. .complete, .error ๊ฐ™์€ ์ •์ง€ ์ด๋ฒคํŠธ๋Š” ํ—ˆ์šฉ.

let strikes = PublishSubject<String>()

strikes
    .ignoreElements()
    .subscribe { _ in print("OUT !") }
    .disposed(by: disposeBag)

strikes.onNext("X")
strikes.onNext("X")
strikes.onNext("X")

strikes.onCompleted()

// ์‹คํ–‰๊ฒฐ๊ณผ
OUT !


2. .elementAt
– ์•ผ๊ตฌ์˜ ์ŠคํŠธ๋ผ์ดํฌ์ฒ˜๋Ÿผ, Observable์—์„œ ๋ฐฉ์ถœ๋œ n๋ฒˆ์งธ ์š”์†Œ๋งŒ ๋ฐฉ์ถœํ•˜๊ณ  ๋‚˜๋จธ์ง€๋Š” ๋ฌด์‹œ.

let strikes = PublishSubject<String>()

strikes
    .elementAt(2)
    .subscribe { print("STRIKE \($0)") }
    .disposed(by: disposeBag)

strikes.onNext("X-0")
strikes.onNext("X-1")
strikes.onNext("X-2")
strikes.onNext("X-3")

strikes.onCompleted()

// ์‹คํ–‰๊ฒฐ๊ณผ
STRIKE next(X-2)
STRIKE completed


3. .filter
– ์š”๊ตฌ์‚ฌํ•ญ์ด ํ•œ ๊ฐ€์ง€ ์ด์ƒ์ผ ๋•Œ ์‚ฌ์šฉ.

let observable = Observable.of(1, 2, 3, 4, 5, 6)

observable
    .filter { $0 > 3 }
    .subscribe { print("\($0)") }
    .disposed(by: disposeBag)

// ์‹คํ–‰๊ฒฐ๊ณผ
next(4)
next(5)
next(6)
completed



Skipping Operators
1. .skip
– ์ฒซ ๋ฒˆ์งธ ์š”์†Œ๋ถ€ํ„ฐ n๊ฐœ์˜ ์š”์†Œ๋ฅผ skip

let observable = Observable.of(1, 2, 3, 4, 5, 6)

observable
    .skip(3)
    .subscribe { print("\($0)") }
    .disposed(by: disposeBag)

// ์‹คํ–‰ ๊ฒฐ๊ณผ
next(4)
next(5)
next(6)
completed


2. .skipWhile
– skip ํ•˜์ง€ ์•Š์„ ๋•Œ๊นŒ์ง€ skip ํ•˜๊ณ  ์ข…๋ฃŒํ•˜๋Š” ์—ฐ์‚ฐ์ž.
– ๋กœ์ง์ด false๊ฐ€ ๋˜์—ˆ์„ ๋•Œ ๋ฐฉ์ถœ.

let observable = Observable.of(1, 2, 3, 4, 5, 6)

observable
    .skipWhile { $0 * 2 < 10 }
    .subscribe { print("\($0)") }
    .disposed(by: disposeBag)

// ์‹คํ–‰ ๊ฒฐ๊ณผ
next(5)
next(6)
completed



3. .skipUntil
– ๋‘ ๊ฐ€์ง€ Observable(Object) A, B. ๋‘ ๊ฐœ๊ฐ€ ์กด์žฌ.
– A ๋Š” ๊ณ„์† ๋ฐฉ์ถœ ์ค‘. B ๊ฐ€ ๋ฐฉ์ถœํ•˜๊ธฐ ์ „๊นŒ์ง€ ๊ณ„์† skip

let subjectA = PublishSubject<Int>()
let subjectB = PublishSubject<Int>() // trigger

subjectA
    .skipUntil(subjectB)
    .subscribe { print("\($0)") }
    .disposed(by: disposeBag)

subjectA.onNext(0)
subjectA.onNext(1)
subjectA.onNext(2)

subjectB.onNext(0) // trigger !

subjectA.onNext(3)
subjectA.onNext(4)

// ์‹คํ–‰ ๊ฒฐ๊ณผ
next(3)
next(4)



Taking Operators
Taking ์€ skip ์˜ ๋ฐ˜๋Œ€ ๊ฐœ๋….

1. .take
– n๋ฒˆ ์งธ๊นŒ์ง€์˜ ์š”์†Œ๋งŒ ๋ฐฉ์ถœ.

let observable = Observable.of(1, 2, 3, 4)

observable
    .take(2)
    .subscribe { print("\($0)") }
    .disposed(by: disposeBag)

// ์‹คํ–‰๊ฒฐ๊ณผ
next(1)
next(2)
completed



2. .takeWhile
.skipWhile ๊ณผ ์›๋ฆฌ๋Š” ๋น„์Šท.
.shipWhile์ด false์ผ ๋•Œ ๋ฐฉ์ถœํ•œ๋‹ค๋ฉด, .takeWhile์€ true์ผ ๋•Œ ๋ฐฉ์ถœ. false ์กฐ๊ฑด์˜ ์š”์†Œ๊ฐ€ ๋“ฑ์žฅํ•˜๋ฉด ๋ฐฉ์ถœ ์ข…๋ฃŒ.

3. .enumerated
– Swift ์˜ enumerated ์™€ ์œ ์‚ฌ.
– Observable์—์„œ ๋ฐฉ์ถœ๋˜๋Š” ์š”์†Œ์˜ index์™€ ๊ฐ’์œผ๋กœ ๋œ ํŠœํ”Œ์„ ์ƒ์„ฑ.

let observable = Observable.of(1, 2, 3, 4)

observable
    .enumerated() // ๐ŸŒŸ
    .take(3)
    .subscribe { print("index: \($0.element?.index) / element: \($0.element?.element)") }
    .disposed(by: disposeBag)

// ์‹คํ–‰ ๊ฒฐ๊ณผ
index: Optional(0) / element: Optional(1)
index: Optional(1) / element: Optional(2)
index: Optional(2) / element: Optional(3)
index: nil / element: nil



4. .takeUntil
– trigger ๊ฐ€ ๋˜๋Š” Observable ์ด ๋ฐฉ์ถœ๋˜๊ธฐ ์ „๊นŒ์ง€๋งŒ ๋ฐฉ์ถœ.

let subjectA = PublishSubject<Int>()
let subjectB = PublishSubject<Int>()

subjectA
    .takeUntil(subjectB)
    .subscribe { print($0) }
    .disposed(by: disposeBag)

subjectA.onNext(0)
subjectA.onNext(1)
subjectA.onNext(2)
subjectA.onNext(3)

subjectB.onNext(100)

subjectA.onNext(4)
subjectA.onNext(5)

// ์‹คํ–‰ ๊ฒฐ๊ณผ
next(0)
next(1)
next(2)
next(3)
completed



Distinct Operators
์ค‘๋ณต๊ฐ’์„ ์ œ์™ธ.

1. .distinctUntilChanged
– ์—ฐ์†ํ•ด์„œ ๊ฐ™์€ ๊ฐ’์ด ์ด์–ด์ง€๋ฉด ๋‚˜์ค‘์— ๋‚˜์˜จ ์ค‘๋ณต๋œ ๊ฐ’์€ ๋ฐฉ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค.

let observable = Observable.of(2, 3, 3, 4, 4, 4, 5, 4)

observable
    .distinctUntilChanged()
    .subscribe { print($0) }
    .disposed(by: disposeBag)

// ์‹คํ–‰๊ฒฐ๊ณผ
next(2)
next(3)
next(4)
next(5)
next(4)
completed



2. .distinctUntilChanged(_:)
– a, b ์˜ ๋‘๊ฐ€์ง€๋ฅผ ์ปค์Šคํ…€ํ•œ ๋น„๊ต๋กœ์ง์œผ๋กœ ๋ฐฉ์ถœ์„ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.



Challnge
– ํ•œ๊ตญ์‹ ์ „ํ™”๋ฒˆํ˜ธ๋ฅผ ํ•„ํ„ฐ๋ง ํ•ด๋ณด์ž.

let phoneNumberObservable = Observable.of(0, 1, 0, 1, 2, 3, 4, 1, 2, 3, 4)

phoneNumberObservable
    .skipWhile { $0 != 0 }
    .filter { $0 < 10 }
    .take(11)
    .toArray()
    .subscribe { print($0) }
    .disposed(by: disposeBag)
// ์กฐ๊ฑด
// 1. 11๋ฒˆ์งธ ์š”์†Œ๊นŒ์ง€
// 2. ๊ฐ’์€ 10 ์ด์ƒ.
// 3. ๊ฐ’์ด 20์ด ๋„˜์–ด๊ฐ€๋ฒ„๋ฆฌ๋ฉด ๋ฐฉ์ถœ ์ข…๋ฃŒ.
// 4. ์—ฐ์†๋œ ์ค‘๋ณต ์•ˆ๋จ.

let observable = Observable.of(10, 5, 2, 11, 12, 13, 11, 11, 13, 12, 12, 4, 21, 1, 11)

observable
    .filter { $0 > 10 }
    .distinctUntilChanged()
    .takeWhile { $0 < 20 }
    .take(11)
    .toArray()
    .subscribe { print($0) }
    .disposed(by: disposeBag)



Filtering Operators in Practice

.share
.subscribe ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด Observable์ด ์ƒ์„ฑ๋˜๋Š”๊ฑธ ๋ฐฉ์ง€.
.subscribe ๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ.


Transforming Operators

Swift์˜ .map, .flatMap๊ณผ ์œ ์‚ฌ.

.toArray
– Observable ์˜ ์š”์†Œ๋ฅผ ํ•˜๋‚˜์˜ Array์˜ ์š”์†Œ๋กœ ํ•œ๋‹ค.

let numbers = Observable.of(1, 2, 3, 4)
numbers
    .subscribe { print($0) }
    .disposed(by: disposeBag)

print(".toArray()")

numbers
    .toArray()
    .subscribe { print($0) }
    .disposed(by: disposeBag)

// ์‹คํ–‰๊ฒฐ๊ณผ
next(1)
next(2)
next(3)
next(4)
completed
.toArray()
success([1, 2, 3, 4])



.map
– Swift์˜ .map๊ณผ ๊ฐ™๋‹ค.

let numbers = Observable.of(1, 2, 3, 4)
numbers
    .subscribe { print($0) }
    .disposed(by: disposeBag)

print(".map")

numbers
    .map { $0 * 2 }
    .subscribe { print($0) }
    .disposed(by: disposeBag)

// ์‹คํ–‰ ๊ฒฐ๊ณผ
next(1)
next(2)
next(3)
next(4)
completed
.map
next(2)
next(4)
next(6)
next(8)
completed



.enumerated
– ๊ฐ๊ฐ์˜ ์š”์†Œ๋ฅผ index์™€ ์š”์†Œ๋กœ ๊ตฌ์„ฑ๋œ ํŠœํ”Œ๋กœ ๋ณ€ํ™˜.


๐Ÿ’ซ BehaviorSubject
– Observable๋กœ์จ, observable ์˜ property๋ฅผ ์ •์˜ํ•  ๋•Œ ์‚ฌ์šฉ.

struct Food {
    var price: BehaviorSubject<Int>
}

let kimchi = Food(price: BehaviorSubject(value: 100))
let chicken = Food(price: BehaviorSubject(value: 1000))

let food = PublishSubject<Food>()

food
    .map { $0.price }
    .subscribe { print($0) }
    .disposed(by: disposeBag)

.compactMap (RxSwift 5 ~)
– Swift์˜ .compactMap๊ณผ ๋™์ผ.

let numbers = Observable.of(1, 2, nil, 4)

numbers
    .compactMap { $0 }
    .subscribe { print($0) }
    .disposed(by: disposeBag)

// ์‹คํ–‰๊ฒฐ๊ณผ
next(1)
next(2)
next(4)
completed




.flatMap
Observable์ด ๊ฐ–๊ณ  ์žˆ๋Š” Observable์˜ ์š”์†Œ๋ฅผ ๋ณ€ํ™˜ํ•˜๊ณ  target observable๋กœ ๋งŒ๋“ ๋‹ค.

struct Food {
    var price: BehaviorSubject<Int>
}

let kimchi = Food(price: BehaviorSubject(value: 100))
let chicken = Food(price: BehaviorSubject(value: 1000))

let food = PublishSubject<Food>()

food
    .flatMap { $0.price }
    .subscribe { print($0) }
    .disposed(by: disposeBag)

food.onNext(kimchi)
kimchi.price.onNext(200)

food.onNext(chicken)
chicken.price.onNext(2000)

kimchi.price.onNext(300)
chicken.price.onNext(3000)

// ์‹คํ–‰๊ฒฐ๊ณผ
next(100)
next(200)
next(1000)
next(2000)
next(300)
next(3000)



.flatMapLatest
.flatMap์—์„œ ์ตœ์‹ ์˜ ๊ฐ’๋งŒ์„ ํ™•์ธํ•˜๊ณ  ์‹ถ์„ ๋•Œ.
flatMapLatest = map + switchLatest
– ์ƒˆ๋กœ์šด ์š”์†Œ๊ฐ€ ๋“ค์–ด์˜ค๋ฉด ์ด์ „์˜ observable์€ ๊ตฌ๋… ํ•ด์ง€.
– ํ™œ์šฉ ์˜ˆ : ๊ฒ€์ƒ‰์ฐฝ์—์„œ ์ƒˆ๋กœ์šด ๋ฌธ์ž๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ์ด์ „ ๋‚ด์šฉ์€ ์—†์• ๊ณ , ์ƒˆ๋กœ์šด ํ‚ค์›Œ๋“œ์— ๋Œ€ํ•œ ์ถ”์ฒœ ํ‚ค์›Œ๋“œ๋ฅผ ๋ณด์—ฌ์ค˜์•ผํ•จ.

struct Food {
    var price: BehaviorSubject<Int>
}

let kimchi = Food(price: BehaviorSubject(value: 100))
let chicken = Food(price: BehaviorSubject(value: 1000))

let food = PublishSubject<Food>()

food
    .flatMapLatest { $0.price }
    .subscribe { print($0) }
    .disposed(by: disposeBag)

food.onNext(kimchi)
kimchi.price.onNext(200)

food.onNext(chicken) // chicken์ด ๋“ค์–ด์™”์œผ๋ฏ€๋กœ kimchi๋Š” ๊ตฌ๋… ํ•ด์ง€.
chicken.price.onNext(2000)

kimchi.price.onNext(300) // ๋ฌด์‹œ๋œ๋‹ค.
chicken.price.onNext(3000)

// ์‹คํ–‰๊ฒฐ๊ณผ
next(100)
next(200)
next(1000)
next(2000)
next(3000)

์ด๋ฒคํŠธ๋ฅผ Observable ๋กœ ๋ณ€ํ™˜
1. .materialize
2. .dematerialize




Combining Operators

Sequence ๋ฅผ ๋ชจ์œผ๊ณ , ๊ฐ๊ฐ์˜ Sequence ๋‚ด์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ‘ํ•ฉ.
Swift ์˜ Array ๋ฅผ ์ƒ๊ฐํ•˜๋ฉด ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๋‹ค ๐Ÿ’ก

Observable์˜ ์•ž์— ๋ณ‘ํ•ฉ
1. .startWith
2. Observable.concat
3. .concat
4. .concatMap

ํ•ฉ์น˜๊ธฐ
1. .merge
2. .merge(maxConcurrent:)

๊ฒฐํ•ฉํ•˜๊ธฐ
1. .combineLatest
4. .zip

Triggers
1. .withLatestFrom
2. .sample

Switch
1. .amb
2. .switchLates

sequence ๋‚ด์˜ ์š”์†Œ๋“ค๊ฐ„์˜ ๊ฒฐํ•ฉ
1. .reduce
2. .scan



Observable์˜ ์•ž์— ๋ณ‘ํ•ฉ

1. .startWith
– ๊ธฐ์กด์˜ Observable ์˜ ์ดˆ๊นƒ๊ฐ’. ๊ฐ€์žฅ ์•ž์— ๋†“์ผ ๊ฐ’์„ ์ถ”๊ฐ€(๋ณ‘ํ•ฉ).

let numbers = Observable.of(1, 2, 3, 4)

numbers
    .startWith(0)
    .subscribe { print($0) }
    .disposed(by: disposeBag)



2. Observable.concat
– ๋ณต์ˆ˜์˜ ์š”์†Œ๋ฅผ ๊ฐ€์ง„ ๋‘ ๊ฐœ์˜ Observable ๋“ค์„ ๋ณ‘ํ•ฉ.
.concat ์œผ๋กœ ๋ณ‘ํ•ฉ๋œ Observable ์ค‘ Error ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ „์ฒด๊ฐ€ ์ข…๋ฃŒ.

let numbers1 = Observable.of(1, 2, 3, 4)
let numbers2 = Observable.of(5, 6, 7)

Observable.concat([numbers1, numbers2])
    .subscribe { print($0) }
    .disposed(by: disposeBag)

// ์‹คํ–‰๊ฒฐ๊ณผ
next(1)
next(2)
next(3)
next(4)
next(5)
next(6)
next(7)
completed



3. .concat

let numbers1 = Observable.of(1, 2, 3, 4)
let numbers2 = Observable.of(5, 6, 7)

numbers1
    .concat(numbers2)
    .subscribe { print($0) }
    .disposed(by: disposeBag)


// ์‹คํ–‰๊ฒฐ๊ณผ
next(1)
next(2)
next(3)
next(4)
next(5)
next(6)
next(7)
completed




4. .concatMap

let key1 = "American Food"
let key2 = "Japanise Food"
let sequences: [String: Observable<String>] = [key1: Observable.of("Hamburger, Hawaian Pizza"),
                 key2: Observable.of("Udon, Sushi")]

Observable.of(key1, key2)
    .concatMap { sequences[$0] ?? .empty() }
    .toArray()
    .subscribe { print($0) }
    .disposed(by: disposeBag)

// ์‹คํ–‰ ๊ฒฐ๊ณผ
success(["Hamburger, Hawaian Pizza", "Udon, Sushi"])





ํ•ฉ์น˜๊ธฐ

1. .merge
– ๋ณต์ˆ˜์˜ sequence ๋ฅผ ๋ณ‘ํ•ฉ.
– ๋ฐฉ์ถœ๋˜๋Š” ์ˆœ์„œ๋Š” sequence์— ์ƒ๊ด€์—†์ด ๋ฐฉ์ถœ๋˜๋Š” ์ˆœ์„œ ๊ทธ๋Œ€๋กœ.

let americanFoodNameSubject = PublishSubject<String>()
let japaneseFoodNameSubject = PublishSubject<String>()

let source = Observable.of(americanFoodNameSubject.asObservable(), japaneseFoodNameSubject.asObservable())

let observable = source.merge()
let disposable = observable.subscribe { print($0) }

americanFoodNameSubject.onNext("hamburger")
americanFoodNameSubject.onNext("hawaian pizza")
japaneseFoodNameSubject.onNext("udon")
americanFoodNameSubject.onNext("hot dog")

disposable.disposed(by: disposeBag)

// ์‹คํ–‰ ๊ฒฐ๊ณผ
next(hamburger)
next(hawaian pizza)
next(udon)
next(hot dog)



2. .merge(maxConcurrent:)
– ๋ณ‘ํ•ฉ๋  ์ˆ˜ ์žˆ๋Š” sequence ์ˆ˜๋ฅผ maxConcurrent ๋กœ ์ œํ•œ.

let observable = source.merge(maxConcurrent: 1)
let disposable = observable.subscribe { print($0) }

americanFoodNameSubject.onNext("hamburger")
americanFoodNameSubject.onNext("hawaian pizza")
japaneseFoodNameSubject.onNext("udon")
americanFoodNameSubject.onNext("hot dog")

disposable.disposed(by: disposeBag)

// ์‹คํ–‰๊ฒฐ๊ณผ
next(hamburger)
next(hawaian pizza)
next(hot dog)




๊ฒฐํ•ฉํ•˜๊ธฐ

1. .combineLatest

https://github.com/fimuxd/RxSwift/blob/master/Lectures/09_Combining%20Operators/Ch9.CombiningOperators.md#1-combinelatestresultselector

– ๊ฐ๊ฐ์˜ ๋ฐฉ์ถœํ•œ ์ตœ์‹ ๊ฐ’์ด ๊ฒฐํ•ฉํ•œ๋‹ค.
– sequence ๋“ค์ด ๊ฐ™์€ ํƒ€์ž…์ด ์•„๋‹ˆ์–ด๋„ ๋œ๋‹ค.

let foods = PublishSubject<String>()
let drinks = PublishSubject<String>()

let combination = Observable
    .combineLatest(foods, drinks) { food, drink in
        "\(food) ๐Ÿ’œ \(drink)"
    }
    .subscribe { print($0) }

foods.onNext("Pizza")
foods.onNext("Udon")
foods.onNext("Kimchi")
drinks.onNext("Coke")
drinks.onNext("Green tea")
drinks.onNext("Water")

combination.disposed(by: disposeBag)

// ์‹คํ–‰๊ฒฐ๊ณผ
next(Kimchi ๐Ÿ’œ Coke)
next(Kimchi ๐Ÿ’œ Green tea)
next(Kimchi ๐Ÿ’œ Water)



4. .zip

– ๊ฐ๊ฐ์˜ sequence ์˜ ์š”์†Œ๋ฅผ ํŠœํ”Œ๋กœ ๋งŒ๋“ ๋‹ค.

let foods = PublishSubject<String>()
let drinks = PublishSubject<String>()

let combination = Observable
    .zip(foods, drinks) { food, drink in
        "\(food) ๐Ÿ’œ \(drink)"
    }
    .subscribe { print($0) }

foods.onNext("Pizza")
foods.onNext("Udon")
foods.onNext("Kimchi")
drinks.onNext("Coke")
drinks.onNext("Green tea")
drinks.onNext("Water")

combination.disposed(by: disposeBag)

// ์‹คํ–‰๊ฒฐ๊ณผ
next(Pizza ๐Ÿ’œ Coke)
next(Udon ๐Ÿ’œ Green tea)
next(Kimchi ๐Ÿ’œ Water)



Triggers
1. .withLatestFrom

์ถœ์ฒ˜

– trigger ๊ฐ€ ๋˜๋Š” sequence์˜ ์š”์†Œ๊ฐ€ ๋ฐฉ์ถœ๋˜๋ฉด ๋ณ‘ํ•ฉ๋œ sequence์˜ ์ตœ๊ทผ ์š”์†Œ๊ฐ€ ๋ฐฉ์ถœ๋œ๋‹ค.

let foods = PublishSubject<String>()
let eatGesture = PublishSubject<Void>()

let observable = eatGesture.withLatestFrom(foods)
    .subscribe { print($0) }

foods.onNext("Pizza")
foods.onNext("Udon")
eatGesture.onNext(())

foods.onNext("Kimchi")
eatGesture.onNext(())
eatGesture.onNext(())

observable.disposed(by: disposeBag)

// ์‹คํ–‰ ๊ฒฐ๊ณผ
next(Udon)
next(Kimchi)
next(Kimchi)



2. .sample
.withLastestFrom ๊ณผ ๋น„์Šทํ•˜์ง€๋งŒ ๊ฐ€์žฅ ์ตœ๊ทผ๊ฐ’์ด trigger์— ์˜ํ•ด ์ด๋ฏธ ๋ฐฉ์ถœ๋˜์—ˆ๋‹ค๋ฉด trigger๊ฐ€ ๋ฐฉ์ถœ๋˜์–ด๋„ ๋ฐฉ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค

let foods = PublishSubject<String>()
let eatGesture = PublishSubject<Void>()

let observable = foods.sample(eatGesture)
    .subscribe { print($0) }

foods.onNext("Pizza")
foods.onNext("Udon")
eatGesture.onNext(())
eatGesture.onNext(())
eatGesture.onNext(())

foods.onNext("Kimchi")
eatGesture.onNext(())
eatGesture.onNext(())

observable.disposed(by: disposeBag)




Switches

1. .amb
– ๋‘ ๊ฐœ์˜ sequence๋ฅผ ๊ตฌ๋…. ๋‘ sequence์˜ ๋ฐฉ์ถœ์„ ๊ธฐ๋‹ค๋ฆฌ๋‹ค๊ฐ€ ๋จผ์ € ๋ฐฉ์ถœ์„ ์‹œ์ž‘๋œ sequence์˜ ์š”์†Œ๋งŒ ๋ฐฉ์ถœ.

let foods = PublishSubject<String>()
let drinks = PublishSubject<String>()

let observable = foods.amb(drinks)
    .subscribe { print($0) }

foods.onNext("Pizza")

drinks.onNext("Coke")
drinks.onNext("Tea")
drinks.onNext("Water")

foods.onNext("Udon")
foods.onNext("Kimchi")

drinks.onNext("Juice")

observable.disposed(by: disposeBag)


// ์‹คํ–‰๊ฒฐ๊ณผ
next(Pizza)
next(Udon)
next(Kimchi)



2. .switchLatest
– ๊ธฐ์ค€์ด ๋˜๋Š” Sequence๊ฐ€ ๋ฐฉ์ถœ๋œ ๋‹ค์Œ ๊ฐ€์žฅ ์ตœ๊ทผ์— ๋ฐฉ์ถœ๋˜๋Š” Sequence์˜ ์š”์†Œ๋งŒ ๋ฐฉ์ถœ๋œ๋‹ค. ์˜ ๋ฐ˜๋ณต

let foods = PublishSubject<String>()
let drinks = PublishSubject<String>()
let order = PublishSubject<String>()

let customer = PublishSubject<Observable<String>>()

let observable = customer.switchLatest()
    .subscribe { print($0) }

foods.onNext("Pizza")

drinks.onNext("Coke")
drinks.onNext("Tea")
drinks.onNext("Water")

foods.onNext("Udon")
foods.onNext("Kimchi")

drinks.onNext("Juice")

observable.disposed(by: disposeBag)

// ์‹คํ–‰ ๊ฒฐ๊ณผ
next(Pizza)
next(Udon)
next(Kimchi)




sequence ๋‚ด์˜ ์š”์†Œ๋“ค๊ฐ„์˜ ๊ฒฐํ•ฉ
1. .reduce
– Sequence์˜ ์š”์†Œ๊ฐ€ ์—ฐ์‚ฐ๋˜์–ด ํ•˜๋‚˜์˜ ์š”์†Œ๋กœ ๋ฐฉ์ถœ๋œ๋‹ค.

let numbers = Observable.of(1, 2, 3)
numbers
    .reduce(0, accumulator: +)
    .subscribe { print($0) }
    .disposed(by: disposeBag)

// ์‹คํ–‰๊ฒฐ๊ณผ
next(6)
completed



2. .scan
– sequence์˜ ์š”์†Œ๊ฐ€ ์ถ”๊ฐ€๋ ๋•Œ ๋งˆ๋‹ค ์—ฐ์‚ฐ๋˜๊ณ , ์—ฐ์‚ฐ๋œ ๊ฐ’์€ ๊ฐ๊ฐ ๋ฐฉ์ถœ๋œ๋‹ค.

let numbers = Observable.of(1, 2, 3)
numbers
    .scan(0, accumulator: +)
    .subscribe { print($0) }
    .disposed(by: disposeBag)

// ์‹คํ–‰ ๊ฒฐ๊ณผ
next(1)
next(3)
next(6)
completed




Time Based Operators

์‹œ๊ฐ„์˜ ํ๋ฆ„์— ๋”ฐ๋ผ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๋™๋˜๋Š” ๊ฒƒ์„ ์‹œ๊ฐ์ ์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

Buffering Operators
1. ๊ณผ๊ฑฐ ์š”์†Œ ๋ฆฌํ”Œ๋ ˆ์ด / .replay()
2. ๋ฌด์ œํ•œ ๋ฆฌํ”Œ๋ ˆ์ด / .replayAll()
3. Controlled buffering / .buffer
4. buffered observables ์˜ window

Time-shifting Operators

1. ๊ตฌ๋… ์ง€์—ฐ / .delaySubscription
2. Delayed elements

Timer Operators

1. Observable.interval
2. Observable.timer
3. Timeout



Buffering Operators
– Buffering ์—ฐ์‚ฐ์ž๋Š” ๊ณผ๊ฑฐ์˜ ์š”์†Œ๋“ค์„ ๊ตฌ๋…์ž์—๊ฒŒ ๋‹ค์‹œ ์žฌ์ƒํ•˜๊ฑฐ๋‚˜, ์ž ์‹œ ๋ฒ„ํผ๋ฅผ ๋‘๊ณ  ์ค„ ์ˆ˜ ์žˆ๋‹ค.
– ์–ธ์ œ ์–ด๋–ป๊ฒŒ ๊ณผ๊ฑฐ์™€ ์ƒˆ๋กœ์šด ์š”์†Œ๋“ค์„ ์ „๋‹ฌํ•  ๊ฒƒ์ธ์ง€ ์ปจํŠธ๋กค.

1. ๊ณผ๊ฑฐ ์š”์†Œ ๋ฆฌํ”Œ๋ ˆ์ด / .replay()
2. ๋ฌด์ œํ•œ ๋ฆฌํ”Œ๋ ˆ์ด / .replayAll()
3. Controlled buffering / .buffer
4. buffered observables ์˜ window

Time-shifting Operators

1. ๊ตฌ๋… ์ง€์—ฐ / .delaySubscription
2. Delayed elements

Timer Operators

1. Observable.interval
2. Observable.timer
3. Timeout


๋‹ต๊ธ€ ๋‚จ๊ธฐ๊ธฐ

์•„๋ž˜ ํ•ญ๋ชฉ์„ ์ฑ„์šฐ๊ฑฐ๋‚˜ ์˜ค๋ฅธ์ชฝ ์•„์ด์ฝ˜ ์ค‘ ํ•˜๋‚˜๋ฅผ ํด๋ฆญํ•˜์—ฌ ๋กœ๊ทธ ์ธ ํ•˜์„ธ์š”:

WordPress.com ๋กœ๊ณ 

WordPress.com์˜ ๊ณ„์ •์„ ์‚ฌ์šฉํ•˜์—ฌ ๋Œ“๊ธ€์„ ๋‚จ๊น๋‹ˆ๋‹ค. ๋กœ๊ทธ์•„์›ƒ /  ๋ณ€๊ฒฝ )

Google photo

Google์˜ ๊ณ„์ •์„ ์‚ฌ์šฉํ•˜์—ฌ ๋Œ“๊ธ€์„ ๋‚จ๊น๋‹ˆ๋‹ค. ๋กœ๊ทธ์•„์›ƒ /  ๋ณ€๊ฒฝ )

Twitter ์‚ฌ์ง„

Twitter์˜ ๊ณ„์ •์„ ์‚ฌ์šฉํ•˜์—ฌ ๋Œ“๊ธ€์„ ๋‚จ๊น๋‹ˆ๋‹ค. ๋กœ๊ทธ์•„์›ƒ /  ๋ณ€๊ฒฝ )

Facebook ์‚ฌ์ง„

Facebook์˜ ๊ณ„์ •์„ ์‚ฌ์šฉํ•˜์—ฌ ๋Œ“๊ธ€์„ ๋‚จ๊น๋‹ˆ๋‹ค. ๋กœ๊ทธ์•„์›ƒ /  ๋ณ€๊ฒฝ )

%s์— ์—ฐ๊ฒฐํ•˜๋Š” ์ค‘