๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
IOS๐ŸŽ/RxSwift

[RxSwift] Combine Operator(CombineLatest, Merge, StartWith, Concat, Zip, WithLastFrom, Sample, SwitchLatest, Debounce)

by Jouureee 2022. 3. 6.

rxSwift์— ๋Œ€ํ•œ ๊ฐ•์˜๋ฅผ ๋“ฃ๋‹ค๊ฐ€ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” operator์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด ๋†“์œผ๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค๋”๋ผ๊ตฌ์š”

๊ทธ๋ž˜์„œ ์˜ค๋Š˜์€ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋˜๋Š” operator๋“ค์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค

๊ณ„์† operator์— ๊ด€ํ•ด ์‚ฌ์šฉํ• ๋•Œ๋งˆ๋‹ค ์—ฌ๊ธฐ์— ์ •๋ฆฌํ•ด ๋†“์„๋ ค๊ตฌ์š” !

 

Combine

์„œ๋กœ ๋‹ค๋ฅธ ์ŠคํŠธ๋ฆผ์„ ํ•˜๋‚˜์˜ ์ŠคํŠธ๋ฆผ์œผ๋กœ ํ•ฉ์น ๋•Œ ์‚ฌ์šฉํ•˜๋Š” operator

 

CombineLatest

 

 

๋‘ observable์—์„œ ์•„์ดํ…œ์„ ๋ฐฉ์ถœํ• ๋•Œ ๊ฐ€์žฅ ์ตœ์‹ ์˜ ์•„์ดํ…œ์„ ๊ฒฐํ•ฉํ•˜๊ณ , ๊ฒฐํ•ฉ๋œ ์•„์ดํ…œ์„ ๋ฐœํ–‰

let left = PublishSubject()  
let right = PublishSubject()

let observable = Observable.combineLatest(left, right, resultSelector: { lastLeft, lastRight in  
"(lastLeft) (lastRight)"  
})

let disposable = observable.subscribe(onNext: { value in  
print(value)  
})

left.onNext(5)  
left.onNext(3)  
right.onNext(2)  
right.onNext(1)  
left.onNext(99)

์ถœ๋ ฅ ๊ฒฐ๊ณผ 

3 2

3 1

99 1

๋‘ observable์ด ๊ฐ๊ฐ ์ตœ์ดˆ ๋ฐœํ–‰๋˜์—ˆ์„๋•Œ ๋ฌถ์–ด ๋ฐฉ์ถœํ•œ๋‹ค.

์ถœ์ฒ˜ : https://min-i0212.tistory.com/16


Merge

 

๋ง๊ทธ๋Œ€๋กœ ๋ณ‘ํ•ฉ์ž…๋‹ˆ๋‹ค. ๋‘๊ฐœ ์ด์ƒ์˜ Observable ์ถœ๋ ฅ์„ ๊ฒฐํ•ฉํ•˜์—ฌ ๋‹จ์ผ Observable์ฒ˜๋Ÿผ ์ž‘๋™ํ•˜๊ฒŒ ํ•จ

mergeํ•˜๊ณ  ์žˆ๋Š” ์—ฌ๋Ÿฌ observable๋“ค์„ ๋™์‹œ์— subscribeํ•˜๋ฉด์„œ ๋จผ์ € ์˜ค๋Š” ์ด๋ฒคํŠธ๋“ค์„ ๋ฐ”๋กœ ์ „๋‹ฌํ•ด์ค€๋‹ค.

let left = PublishSubject<String>()
let right = PublishSubject<String>()

let source = Observable.of(left.asObservable(), right.asObservable())

let observable = source.merge()

let disposable = observable.subscribe(onNext: { value in
    print(value)
})

var leftValues = ["Berlin", "Munich", "Frankfurt"]
var rightValues = ["Madrid", "Barcelona", "Valencia"]

repeat {
    if arc4random_uniform(2) == 0 {
        if !leftValues.isEmpty {
            left.onNext("Left:  " + leftValues.removeFirst())
        }
    } else if !rightValues.isEmpty {
        right.onNext("Right: " + rightValues.removeFirst())
    }
} while !leftValues.isEmpty || !rightValues.isEmpty

disposable.dispose()

์ถœ๋ ฅ ๊ฒฐ๊ณผ (ํ•ญ์ƒ ๋‹ค๋ฅด๊ฒŒ ๋‚˜์˜จ๋‹ค)

Left: Berlin 

Left: Munich 

Right: Madrid 

Right: Barcelona 

Right: Valencia 

Left: Frankfurt

 

์ถœ์ฒ˜: https://rhammer.tistory.com/309 

 


StartWith

Observable ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— ์ง€์ •๋œ ํ•ญ๋ชฉ ์‹œํ€€์Šค๋ฅผ ๋ฐฉ์ถœ

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

Concat

2๊ฐœ ์ด์ƒ์˜ observable์„ ์ˆœ์„œ๋Œ€๋กœ ๋ฌถ์Œ

let start = Observable.of(1,2,3,4)
let end = Observable.of(5, 6, 7, 8)
let observable = Observable.concat(start, end)
observable.subscribe(onNext: {
    print($0)
}).disposed(by: disposeBag)

Zip

๋‘ ๊ฐœ ์ด์ƒ์˜ Observable์—์„œ ๋ฐœํ–‰ ์ˆœ์„œ๊ฐ€ ๊ฐ™์€ ์•„์ดํ…œ์„ ๋ฌถ์–ด ๋ฐœํ–‰

enum Weather { case cloudy, sunny }

let left: Observable < Weather > = Observable.of(.sunny, .cloudy, .cloudy, .sunny) 
let right = Observable.of("Lisbon", "Copenhagen", "London", "Madrid", "Vienna")

let observable = Observable
.zip(left, right, resultSelector: { (weather, city) in 
return "It's \(weather) in \(city)."
})

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

์ถœ๋ ฅ ๊ฒฐ๊ณผ

It's sunny in Lisbon. 

It's cloudy in Copenhagen. 

It's cloudy in London. 

It's sunny in Madrid.

 

์ถœ์ฒ˜ : https://rhammer.tistory.com/311?category=649741

 


WithLastFrom

๋‘ observable ์ค‘ ์ฒซ๋ฒˆ์งธ observable์—์„œ ์•„์ดํ…œ์ด ๋ฐฉ์ถœ๋ ๋•Œ๋งˆ๋‹ค ๊ทธ ์•„์ดํ…œ์„ ๋‘๋ฒˆ์งธ observable์˜ ๊ฐ€์žฅ ์ตœ๊ทผ ์•„์ดํ…œ๊ณผ ๊ฒฐํ•ฉํ•ด ๋ฐฉ์ถœ 

let disposeBag = DisposeBag()
    
let numSubject  = PublishSubject<Int>()
let charSubject = PublishSubject<String>()
    
numSubject
    .withLatestFrom(charSubject) { "\($0)\($1)"}
    .subscribe(onNext: { print($0) })
    .disposed(by:disposeBag)
    
numSubject.onNext(1)     // ์•„์ดํ…œ ๋ฐฉ์ถœ๋˜์ง€ ์•Š์Œ : charSubject์—์„œ ๋ฐฉ์ถœ๋œ ์•„์ดํ…œ์ด ์•„์ง 1๊ฐœ๋„ ์—†์œผ๋ฏ€๋กœ
    
charSubject.onNext("A")
    
numSubject.onNext(2)     // 2A
    
charSubject.onNext("B")
    
charSubject.onNext("C")
charSubject.onNext("D")
    
numSubject.onNext(3)     // 3D charSubject์—์„œ ๊ฐ€์žฅ ์ตœ๊ทผ ์•„์ดํ…œ D์™€ ๊ฒฐํ•ฉ
numSubject.onNext(4)     // 4D
numSubject.onNext(5)     // 5D

์ถœ๋ ฅ ๊ฒฐ๊ณผ

2A

3D

4D

5D

ํŠน์ • ๊ฐ’์„ ํŠน์ • ์ด๋ฒคํŠธ๋ฅผ ํ†ตํ•ด ์ตœ์‹  ๊ฐ’์„ ๋ฐ›์•„์˜ค๋Š”๋ฐ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ถœ์ฒ˜ : https://jusung.github.io/withLatestFrom/


Sample

๋‘ observable ์ค‘ ๋‘๋ฒˆ์งธ observable์—์„œ ์•„์ดํ…œ์ด ๋ฐฉ์ถœ๋ ๋•Œ๋งˆ๋‹ค ์ฒซ๋ฒˆ์งธ observable๋‚ด ๊ฐ€์žฅ ์ตœ์‹  ๊ฐ’์„ ๋ฐฉ์ถœํ•œ๋‹ค. ๋ฐฉ์ถœ๋œ ๊ฐ’์ด ์žˆ๋‹ค๋ฉด ๊ฐ™์€ ๊ฐ’์„ ๋ฐฉ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค.

withLatestFrom(_:) ์™€ distinctUntilChanged()์„ ํ•ฉ์ณ ๋†“์€ ๊ฒƒ

 


SwitchLatest

๋‘ ๊ฐœ ์ด์ƒ์˜ Observable์—์„œ ๊ฒฐํ•ฉํ•˜๋˜ ๊ฐ€์žฅ ์ตœ์‹ ์˜ ์•„์ดํ…œ์œผ๋กœ ๋ฐœํ–‰๋ฉ๋‹ˆ๋‹ค.

// 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) 
}).disposed(by: disposedBag)

// 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()

์ถœ๋ ฅ ๊ฒฐ๊ณผ

Some text from sequence one

one More text from sequence two 

Hey it's three. I win. 

Nope. It's me, one!

 

์ถœ์ฒ˜: https://rhammer.tistory.com/350?category=649741 

 


Debounce

ํƒ€์ด๋จธ๋ฅผ ์ง€์ •ํ•ด๋‘๊ณ  ํƒ€์ด๋จธ๊ฐ€ ๋๋‚œ ์‹œ์ ์—์„œ ๊ฐ€์žฅ ์ตœ์‹ ์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ด์ค๋‹ˆ๋‹ค.

'IOS๐ŸŽ > RxSwift' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[RxSwift] Driver๋ž€ ? (feat. bind)  (0) 2022.03.21
[RxSwift] Traits ์ด๋ž€  (0) 2022.03.19
[RxSwift] Disposable DisposeBag ์ด๋ž€  (0) 2022.03.17
[RxSwift] 2. Subject์™€ Relay  (0) 2021.11.20
[RxSwift ] 1. Observable์ด๋ž€  (0) 2021.11.15

๋Œ“๊ธ€