Skip to content

Latest commit

ย 

History

History
1209 lines (958 loc) ยท 29.2 KB

File metadata and controls

1209 lines (958 loc) ยท 29.2 KB

OperatorPractice

map

๋ฐฉ์ถœ๋˜๋Š” ๊ฐ’์— ์–ด๋–ค ๋ณ€ํ˜•์„ ์ฃผ์–ด ๋ฐฉ์ถœํ•˜๋Š” ์˜คํผ๋ ˆ์ดํ„ฐ

#1

Observable.of(1, 2, 3)
    .map({ (result: Int) -> Int in
      result * 10
    })
    .subscribe(onNext:{
      print($0)
    })
    .disposed(by: disposeBag)

๊ฒฐ๊ณผ

10
20
30

#2

Observable.of(1, 2, 3)
    .map({ (result: Int) -> String in
      "\(result)"
    })
    .subscribe(onNext:{
      print("String: " + $0)
    })
  // onNext๊ฐ€ ์—†์œผ๋ฉด Event<Element> ๋ฅผ ๋ฐ›๋Š”๋ฐ ์ด๋Š” next, error ์ด๋Ÿฐ ์ด๋ฒคํŠธ๋ฅผ ํ•ธ๋“ค๋ง ํ•˜๊ธฐ ์œ„ํ•จ์ž„.
//    .subscribe({
//      print("String: " + $0)
//      switch $0{
//      case let .next(value):
//        print(value)
//      case let .error(error):
//        print(error)
//      default:
//        print("finished")
//      }
//    })
    .disposed(by: disposeBag)

๊ฒฐ๊ณผ

String: 1
String: 2
String: 3

enumerated

index์™€ value๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์•„์„œ ๊ฐ’์œผ๋กœ ๋ฆฌํ„ด

Observable.of(1, 2, 3, 4, 5)
    .enumerated()
    .map({ (index: Int, value: Int) -> String in
      index > 3 ? "\(value)" : "x"
    })
    .subscribe(onNext:{
      print($0)
    })
    .disposed(by: disposeBag)

๊ฒฐ๊ณผ

x
x
x
x
5

flatMap

์ด๋ฒคํŠธ๋ฅผ ๋‹ค๋ฅธ Observable๋กœ ๋ณ€๊ฒฝ

Observable ์‹œํ€€์Šค์˜ element๋‹น ํ•œ๊ฐœ์˜ ์ƒˆ๋กœ์šด Observable ์‹œํ€€์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ์ƒ์„ฑ๋œ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ƒˆ๋กœ์šด ์‹œํ€€์Šค๋ฅผ ํ•˜๋‚˜์˜ ์‹œํ€€์Šค๋กœ ๋งŒ๋“ค์–ด ์ค€๋‹ค.

Observer in Observer๋ฅผ ๋‹ค๋ฃฌ๋‹ค. (Observer ์•ˆ์— Observer์ด๋ฉฐ, ๋‚ด๋ถ€ Observable์„ inner Observable์ด๋ผ ํ•œ๋‹ค. Observable์•ˆ์— ์žˆ๋Š” Observable,)

#1

Observable.of(1, 2, 3)
    .flatMap({ (result: Int) -> Observable<String> in
      Observable.just("\(result)")
    })
    .subscribe(onNext:{ (result: String) in
      print("String: " + result)
    })
    .disposed(by: disposeBag)

๊ฒฐ๊ณผ

String: 1
String: 2
String: 3

#2

๋น„๋™๊ธฐ ์ฒ˜๋ฆฌํ•  ๋•Œ ๋งŽ์ด ์“ฐ์ž„

https://jcsoohwancho.github.io/2019-09-09-Rxswift%EC%97%B0%EC%82%B0%EC%9E%90-flatmap/

// 1์ดˆ๋งˆ๋‹ค second๋ฅผ ๋ฐฉ์ถœ
let timer1 = Observable<Int>
	.interval(RxTimeInterval.seconds(1), scheduler: MainScheduler.instance)
	.map({"o1: \($0)"})
// 2์ดˆ๋งˆ๋‹ค second๋ฅผ ๋ฐฉ์ถœ
let timer2 = Observable<Int>
	.interval(RxTimeInterval.seconds(2), scheduler: MainScheduler.instance)
	.map({"o2: \($0)"})

Observable.of(timer1, timer2)
    .flatMap({ (emit: Observable<String>) -> Observable<String> in
      emit
    })
    .subscribe({ (result: Event<String>) -> Void in
      print(result)
      switch result{
      case let .next(value):
        print(value)
      default:
        print("finished")
      }
    })
    .disposed(by: disposeBag)

๊ฒฐ๊ณผ

next(o1: 0)
o1: 0
next(o1: 1)
o1: 1
next(o2: 0)
o2: 0
next(o1: 2)
o1: 2
next(o1: 3)
o1: 3
next(o2: 1)
o2: 1
next(o1: 4)
o1: 4
next(o1: 5)
o1: 5
next(o2: 2)
o2: 2

Question

#1

map

Observable.of(timer1, timer2)
 .map({ (emit: Observable<String>) -> Observable<String> in
   emit
 })
 .subscribe(onNext: { (result: Observable<String>) in
   print(result)
 })
 .disposed(by: disposeBag)

๊ฒฐ๊ณผ

RxSwift.(unknown context at $12071da78).Map<Swift.Int, Swift.String>
RxSwift.(unknown context at $12071da78).Map<Swift.Int, Swift.String>
next(o1: 0)
o1: 0
next(o1: 1)
o1: 1
next(o2: 0)
o2: 0
next(o1: 2)
o1: 2
next(o1: 3)
o1: 3
next(o2: 1)
o2: 1
next(o1: 4)
o1: 4
next(o1: 5)
o1: 5
next(o2: 2)
o2: 2

flatMap

Observable.of(timer1, timer2)
 .flatMap({ (emit: Observable<String>) -> Observable<String> in
   emit
 })
 .subscribe(onNext: { (result: String) -> Void in
   print(result)
 })
 .disposed(by: disposeBag)

๊ฒฐ๊ณผ

o1: 0
o1: 1
o2: 0
o1: 2
o1: 3
o2: 1
o1: 4
o1: 5
o2: 2

map์€ Observable๊ฐ’ ๊ทธ๋Œ€๋กœ ๋ฐ›๋Š” ๋ฐ˜๋ฉด์—: Observable --> subscribe({ Observable ... })

flatMap์€ ์–ธ๋ž˜ํ•‘ํ•ด์„œ ๋ฐ›๊ณ  ์žˆ์Œ: Observable --> subscribe({ Element ... })

์™œ ์ด๋Ÿฐ์ผ์ด ๋ฐœ์ƒํ• ๊นŒ?

# ๋” ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ...

map

Observable.of(1, 2, 3)
 .map({ (emit: Int) -> Observable<Int> in
   Observable.just(emit)
 })
 .subscribe(onNext:{ (result: Observable<Int>) in
   print(result)
 })
 .disposed(by: disposeBag)

flatMap

Observable.of(1, 2, 3)
// return์€ Observable<Int> ์ธ๋ฐ
 .flatMap({ (emit: Int) -> Observable<Int>/*๐ŸŒŸ*/ in
   Observable.just(emit)
 })
// subscribe์—์„œ ๋ฐ›๋Š” ๊ฐ’์€ upwrapping
 .subscribe(onNext:{ (result: Int)/*๐ŸŒŸ*/ in
   print(result)
 })
 .disposed(by: disposeBag)

map, flatMap์—์„œ์˜ return ํƒ€์ž…๋งŒ ๋‹ค๋ฅด๊ณ  subscribe์—์„œ ๋ฐ›๋Š” ๊ฐ’์€ ํƒ€์ž…์ด ๊ฐ™์Œ.

flatMap์˜ ๊ฒฝ์šฐ Observable์„ ๋ฆฌํ„ดํ•˜๋Š”๋ฐ ๋ฐ›๋Š” ๊ฐ’์€ unwrapping ํ•œ ๊ฐ’์ž„. ์™œ?

element๋‹น ์ƒˆ๋กœ์šด Observable ์‹œํ€€์Šค๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— return๊ฐ’์ด Observable์ด๋‹ค. ํ•˜๋‚˜์˜ ์‹œํ€€์Šค(subscribe)๋ฅผ ๋งŒ๋“ค์—ˆ๊ณ , ๊ฑฐ๊ธฐ์— ๋Œ€ํ•œ value๋ฅผ ํ•ธ๋“ค๋งํ•˜๋‹ˆ๊นŒ ๋‹น์—ฐํžˆ unwrapping๋œ ๊ฐ’์ด์–ด์•ผ ํ•œ๋‹ค.

(์•„๋ž˜ Answer๋ฅผ ๋ณด์ž)

Answer

https://rhammer.tistory.com/300 ์—์„œ ๋‹ต์„ ์ฐพ์„ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

์šฐ์„  flatMap์ด ์–ด๋–ค ๊ฒƒ์ธ์ง€ ๋ถ€ํ„ฐ ์ž์„ธํžˆ ๋ณผ ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

๋ฌธ์„œ์—๋Š” flatMap์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜ํ•˜๊ณ  ์žˆ๋‹ค.

Projects each element of an observable sequence to an observable sequence and merges the resulting observable sequences into one observable sequence

Observable์‹œํ€€์Šค์˜ element๋‹น ํ•œ ๊ฐœ์˜ ์ƒˆ๋กœ์šด Observable ์‹œํ€€์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ์ƒ์„ฑ๋œ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ƒˆ๋กœ์šด ์‹œํ€€์Šค๋ฅผ ํ•˜๋‚˜์˜ ์‹œํ€€์Šค๋กœ ํ•ฉ์ณ์ค€๋‹ค.

๊ธ€๋งŒ ๋ดค์„ ๋•Œ๋Š” ์ดํ•ด๊ฐ€ ์ž˜์•ˆ๊ฐ”๋Š”๋ฐ ๊ทธ๋ฆผ์„ ๋ณด๋ฉด ์•Œ ์ˆ˜ ์žˆ๋‹ค.

image-20220306184835403

  1. 01 ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ flatMap์„ ๋งŒ๋‚˜ ์ƒˆ๋กœ์šด ์‹œํ€€์Šค๊ฐ€ ์ƒ๊ฒผ๋‹ค. ์ด ์‹œํ€€์Šค๋Š” 01์—˜๋ฆฌ๋จผํŠธ์˜ vlaue์— ๋Œ€ํ•œ ์‹œํ€€์Šค๋‹ค.

    ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ์‹œํ€€์Šค์— 10 ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ๊ณ , ์ตœ์ข… ์‹œํ€€์Šค(์ œ์ผ ํ•˜๋‹จ ์‹œํ€€์Šค)๋กœ ์ „๋‹ฌ๋˜์—ˆ๋‹ค.

    ์ฆ‰, 01์—˜๋ฆฌ๋จผํŠธ์˜ value์— ๋ณ€๋™์ด ์žˆ์œผ๋ฉด, ์ด ์‹œํ€€์Šค์— ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์ด๋‹ค.(์ค‘์š”)

  2. 02 ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ flatMap์„ ๋งŒ๋‚˜ ์ƒˆ๋กœ์šด ์‹œํ€€์Šค๊ฐ€ ์ƒ๊ฒผ๋‹ค. ์ด ์‹œํ€€์Šค๋Š” 02์—˜๋ฆฌ๋จผํŠธ์˜ value์— ๋Œ€ํ•œ ์‹œํ€€์Šค๋‹ค.

    ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ์‹œํ€€์Šค์— 20 ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ๊ณ , ์ตœ์ข… ์‹œํ€€์Šค๋กœ ์ „๋‹ฌ๋˜์—ˆ๋‹ค.

    ์ฆ‰, 02์—˜๋ฆฌ๋จผํŠธ์˜ value์— ๋ณ€๋™์ด ์žˆ์œผ๋ฉด, ์ด ์‹œํ€€์Šค์— ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

  3. 01 ์—˜๋ฆฌ๋จผํŠธ์˜ value์— ๋ณ€๋™์ด ์ƒ๊ฒผ๋‹ค. 1์—์„œ 4๋กœ ๋ฐ”๋€ ๊ฒƒ.(๊ทธ๋ฆผ์—๋Š” ํ‘œ์‹œ ์•ˆํ•จ)

    flatMap์ด ์ƒ์„ฑํ•œ ์‹œํ€€์Šค ์ค‘ 01์—˜๋ฆฌ๋จผํŠธ์— ํ•ด๋‹นํ•˜๋Š” ์‹œํ€€์Šค์— 40์ด๋ผ๋Š” ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ์ตœ์ข… ์‹œํ€€์Šค๋กœ ์ „๋‹ฌ๋˜์—ˆ๋‹ค.

  4. 02 ์—˜๋ฆฌ๋จผํŠธ์˜ value์— ๋ณ€๋™์ด ์ƒ๊ฒผ๋‹ค. 2์—์„œ 5๋กœ ๋ฐ”๋€ ๊ฒƒ.

    flatMap์ด ์ƒ์„ฑํ•œ ์‹œํ€€์Šค ์ค‘ 02์—˜๋ฆฌ๋จผํŠธ์— ํ•ด๋‹นํ•˜๋Š” ์‹œํ€€์Šค์— 50์ด๋ผ๋Š” ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ์ตœ์ข… ์‹œํ€€์Šค๋กœ ์ „๋‹ฌ๋˜์—ˆ๋‹ค.

flatMap์€ ํ•œ ์‹œํ€€์Šค์˜ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์ „๋‹ฌ๋ฐ›์•„ ์ด๋ฅผ ๋ณ€ํ˜•ํ•œ ์ƒˆ๋กœ์šด ์‹œํ€€์Šค๋ฅผ ๋งŒ๋“ค๊ณ (์—˜๋ฆฌ๋จผํŠธ ํ•˜๋‚˜ ๋‹น ์‹œํ€€์Šคํ•˜๋‚˜ ์ƒ์„ฑ) ์ด ์‹œํ€€์Šค์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ชจ๋“  ์ด๋ฒคํŠธ๋ฅผ ์ตœ์ข… ์‹œํ€€์Šค๋กœ ์ „๋‹ฌํ•œ๋‹ค.

์ฝ”๋“œ๋ฅผ ๋ณด์ž

struct Student{
  var score: BehaviorSubject<Int>
}

// Student ํƒ€์ž…์˜ ๋ณ€์ˆ˜ 2๊ฐœ๋ฅผ ์ƒ์„ฑ ryan์€ 80, charlotte๋Š” 90์œผ๋กœ ์ดˆ๊ธฐํ™” ๋˜์–ด์žˆ๋‹ค.
let ryan = Student(score: BehaviorSubject(value: 80))
var charlotte = Student(score: BehaviorSubject(value: 90))

let student = PublishSubject<Student>()

// student์˜ ์‹œํ€€์Šค๋ฅผ ๋ณ€ํ™˜ํ•œ๋‹ค.
student
// Student ์—์„œ Observable<Int>์œผ๋กœ ๋ณ€ํ™˜
	.flatMap({ (element: Student) -> Observable<Int> in
  	element.score
	})
  .subscribe(onNext:{ (result: Int) in
  	print(result)
	})
  .disposed(by: disposeBag)

๊ทธ๋ฆผ์œผ๋กœ ๋ณด๋ฉด ์ด๋ ‡๋‹ค.

image-20220306200145486

next ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ ์‹œ์ผœ ์–ด๋–ค ๊ฒฐ๊ณผ๋ฅผ ๋‚ด๋Š”์ง€ ๋ณด์ž

student.onNext(ryan)
ryan.score.onNext(85)
student.onNext(charlotte)
charlotte.score.onNext(95)
charlotte.score.onNext(100)

๊ฒฐ๊ณผ

80
85
90
95
100

๊ฒฐ๊ณผ๊ฐ€ ๊ทธ๋ ‡๊ฒŒ ์ค‘์š”ํ•œ ๊ฑด ์•„๋‹ˆ๊ณ , ์–ด๋–ค ์ผ์ด ์ผ์–ด๋‚ฌ๋Š”์ง€๊ฐ€ ์ค‘์š”ํ•˜๋‹ค.

flatMap์€ observable์˜ element๋ณ€ํ™”๋ฅผ ๊ณ„์† ๊ด€์ฐฐํ•˜๊ณ  ์žˆ๋‹ค. (ryan์˜ score (Observable์ด๋‹ค.)์— next ์ด๋ฒคํŠธ๋ฅผ ๋ฐฉ์ถœํ•˜๋ฉด flatMap์ด ์•Œ์•„์ฐจ๋ฆฐ๋‹ค.)

๊ทธ๋ฆผ์œผ๋กœ ๋ณด๋ฉด ์ด๋ ‡๋‹ค.

image-20220306200927997

์™œ ์“ฐ๋Š”์ง€์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ธฐ ์œ„ํ•ด map๊ณผ ๋น„๊ตํ•ด๋ณด๊ฒ ๋‹ค.

student
    .map({ (element: Student) -> Observable<Int> in
      element.score
    })
    .subscribe(onNext:{ (result: Observable<Int>) in
      result.subscribe(onNext:{
        print($0)
      })
        .disposed(by: disposeBag)
    })
    .disposed(by: disposeBag)

student.onNext(ryan)
ryan.score.onNext(85)
student.onNext(charlotte)
charlotte.score.onNext(95)
charlotte.score.onNext(100)

๊ฒฐ๊ณผ

80
85
90
95
100

๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด๊ธฐ ์œ„ํ•ด์„œ๋Š” subscribe์•ˆ์— subscribe๋ฅผ ํ•˜๋‚˜ ๋” ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค.

๊ฒฐ๊ตญ์—๋Š” ์ด์ง“๊ฑฐ๋ฆฌ(subscribe์•ˆ์— subscribeํ•˜๋‚˜ ๋” ๋„ฃ๋Š” ๊ฑฐ)๋ฅผ ์•ˆํ•˜๋ ค๊ณ  flatMap์„ ์“ด๋‹ค.

์ •๋ฆฌํ•˜์ž๋ฉด

flatMap์€ Observable์‹œํ€€์Šค์˜ element๋‹น ํ•˜๋‚˜์˜ ์ƒˆ๋กœ์šด Observable ์‹œํ€€์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ์ƒ์„ฑ๋œ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ƒˆ๋กœ์šด ์‹œํ€€์Šค๋ฅผ ํ•˜๋‚˜์˜ ์‹œํ€€์Šค๋กœ ํ•ฉ์ณ์ค€๋‹ค.

Observable.of(1, 2, 3)
// element( result: Int )๋‹น ํ•˜๋‚˜์˜ ์ƒˆ๋กœ์šด Observable์‹œํ€€์Šค( Observable<String> )์„ ์ƒ์„ฑ
    .flatMap({ (result: Int) -> Observable<String> in
			...
		})
// ์ด๋ ‡๊ฒŒ ์ƒ์„ฑ๋œ ์—ฌ๋Ÿฌ๊ฐœ์˜ ์‹œํ€€์Šค๋ฅผ ํ•˜๋‚˜์˜ ์‹œํ€€์Šค( subscribe๋กœ ํ•˜๋‚˜์˜ ์‹œํ€€์Šค )๋กœ ํ•ฉ์ณ์ค€๋‹ค.
		.subscribe(onNext:{ (result: String) in
			...
    })
		.disposed(by: disposeBag)

์œ„์˜ Question #1 ์— ๋Œ€ํ•œ ๋‹ต์ด ๋œ๋‹ค.

element๋‹น ์ƒˆ๋กœ์šด Observable ์‹œํ€€์Šค๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— return๊ฐ’์ด Observable์ด๋‹ค. ํ•˜๋‚˜์˜ ์‹œํ€€์Šค(subscribe)๋ฅผ ๋งŒ๋“ค์—ˆ๊ณ , ๊ฑฐ๊ธฐ์— ๋Œ€ํ•œ value๋ฅผ ํ•ธ๋“ค๋งํ•˜๋‹ˆ๊นŒ ๋‹น์—ฐํžˆ unwrapping๋œ ๊ฐ’์ด์–ด์•ผ ํ•œ๋‹ค.

flatMapLatest

https://rhammer.tistory.com/303 ๋ฅผ ์ฐธ๊ณ  ํ–ˆ์Œ.

๊ธฐ์กด ์˜ต์ €๋ฒ„๋ธ”์ด ๋™์ž‘ํ•˜๊ณ  ์žˆ๋Š” ๋„์ค‘์— ์ƒˆ๋กœ์šด ์˜ต์ €๋ฒ„๋ธ”์ด ์ „๋‹ฌ๋˜๋ฉด ๊ธฐ์กด๊ฒƒ์€ ๋Š๊ธฐ๊ฒŒ ๋˜๋Š” ๊ฒƒ์„ ์ œ์™ธํ•˜๊ณ ๋Š” flatMap๊ณผ ๋™์ž‘์ด ๋˜‘๊ฐ™์Œ.

flatMapLatest๋Š” flatMap๊ณผ switchLatest๋‘๊ฐœ๊ฐ€ ํ•ฉ์ณ์ง„ ํ˜•ํƒœ์ด๋‹ค.

switchLatest๋Š” Observer in Observer ๋ฅผ ๋‹ค๋ฃฌ๋‹ค. ๊ฐ€์žฅ ์ตœ๊ทผ์— ์ถ”๊ฐ€๋œ ์‹œํ€€์Šค์˜ inner Observable๋งŒ ๋„˜๊ฒจ์ค€๋‹ค.

์ฆ‰, switchLatest์™€ flatMap์„ ํ•ฉ์นœ flatMapLatest๋Š” ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ถ”๊ฐ€๋œ ์‹œํ€€์Šค์˜ inner Observable ์ด๋ฒคํŠธ๋งŒ subscribeํ•˜๊ฒŒ ๋œ๋‹ค.

๊ทธ๋ฆผ์„ ๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

image-20220306223556055

  1. flatMap๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ 01 ์—˜๋ฆฌ๋จผํŠธ์˜ value์— ํ•ด๋‹นํ•˜๋Š” ์‹œํ€€์Šค๊ฐ€ ์ƒ๊ธด๋‹ค. 01์—˜๋ฆฌ๋จผํŠธ์˜ ์ตœ์ดˆ value์ธ 1์— 10์„ ๊ณฑํ•˜์—ฌ ์ตœ์ข… ์‹œํ€€์Šค๋กœ ์ „๋‹ฌ๋œ๋‹ค.

  2. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ 02์—˜๋ฆฌ๋จผํŠธ์˜ value์— ํ•ด๋‹นํ•˜๋Š” ์‹œํ€€์Šค๊ฐ€ ์ƒ๊ธด๋‹ค. 02์—˜๋ฆฌ๋จผํŠธ์˜ ์ตœ์ดˆ value์ธ 2์— 10์„ ๊ณฑํ•˜์—ฌ ์ตœ์ข… ์‹œํ€€์Šค๋กœ 20์ด ์ „๋‹ฌ๋œ๋‹ค.

    ๊ทธ๋ฆฌ๊ณ  01์—˜๋ฆฌ๋จผํŠธ์˜ value๊ฐ€ 3์œผ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค. 01์‹œํ€€์Šค์—๋Š” 30์ด ์ „๋‹ฌ๋˜์—ˆ๋‹ค.

    ํ•˜์ง€๋งŒ ์ตœ์ข… ์‹œํ€€์Šค์—๋Š” ์ „๋‹ฌ๋˜์ง€ ์•Š๋Š”๋‹ค. ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— ์ƒ์„ฑ๋œ ์‹œํ€€์Šค์ธ 02์‹œํ€€์Šค๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ 01์‹œํ€€์Šค๋Š” ์•ž์œผ๋กœ ๊ณ„์† ๋ฌด์‹œ๋œ๋‹ค.

  3. 03์—˜๋ฆฌ๋จผํŠธ์— ํ•ด๋‹นํ•˜๋Š” ์‹œํ€€์Šค๊ฐ€ ์ƒ๊ธด๋‹ค. 03์—˜๋ฆฌ๋จผํŠธ์˜ ์ตœ์ดˆ value์ธ 4์— 10์„ ๊ณฑํ•˜์—ฌ ์ตœ์ข… ์‹œํ€€์Šค๋กœ 40์ด ์ „๋‹ฌ๋œ๋‹ค.

    ๊ทธ๋ฆฌ๊ณ  02์—˜๋ฆฌ๋จผํŠธ์˜ value๊ฐ€ 5๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค. 02์‹œํ€€์Šค์—๋Š” 50์ด ์ „๋‹ฌ๋˜์—ˆ๋‹ค.

    ํ•˜์ง€๋งŒ ์ตœ์ข… ์‹œํ€€์Šค์—๋Š” ์ „๋‹ฌ๋˜์ง€ ์•Š๋Š”๋‹ค. ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— ์ƒ์„ฑ๋œ ์‹œํ€€์Šค์ธ 03์‹œํ€€์Šค๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ 02์‹œํ€€์Šค๋Š” ์•ž์œผ๋กœ ๊ณ„์† ๋ฌด์‹œ๋œ๋‹ค.

    ๊ทธ๋ฆฌ๊ณ  03์—˜๋ฆฌ๋จผํŠธ์˜ value๊ฐ€ 6์œผ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค. 03์‹œํ€€์Šค์—๋Š” 60์ด ์ „๋‹ฌ๋˜์—ˆ๋‹ค.

    ์ตœ์ข… ์‹œํ€€์Šค์—๋Š” 60์ด๋ผ๋Š” ๊ฐ’์ด ์ „๋‹ฌ๋˜์—ˆ๋‹ค. 03์‹œํ€€์Šค๋Š” ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— ์ƒ์„ฑ๋œ ์‹œํ€€์Šค์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋„คํŠธ์›Œํฌ ํ†ต์‹ ์—์„œ ๋งŽ์ด ์‚ฌ์šฉ๋จ. ์˜ˆ๋ฅผ ๋“ค์–ด ๊ฒ€์ƒ‰์–ด ์ž๋™์™„์„ฑ ๊ฐ™์ด G๋งŒ ์ณค์„ ๋•Œ ๋‚˜์˜ค๋Š” ๊ฒƒ๊ณผ GO๋ฅผ ์ณค์„ ๋•Œ ๋‚˜์˜ค๋Š” ๊ฒƒ์ด ๋‹ค๋ฅด๋“ฏ ์‚ฌ์šฉ์ž๊ฐ€ ๋งˆ์ง€๋ง‰์— ์นœ ๋ฌธ์ž์—ด์— ๋Œ€ํ•ด์„œ ์ž๋™์™„์„ฑ์„ ์‹œ์ผœ์ฃผ๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. G์—์„œ ์ด์–ด์ง€๋Š” ๋™์ž‘์ด ๋Š๊ธฐ๊ณ  ๋งˆ์ง€๋ง‰์— ๋ฐฉ์ถœ๋œ GO๋กœ ์ด์–ด์ง€๋Š” ๋™์ž‘๋งŒ ์‚ด์•„์žˆ๋Š” ๊ฒƒ

#1

struct Student{
  var score: BehaviorSubject<Int>
}

// Student ํƒ€์ž…์˜ ๋ณ€์ˆ˜ 2๊ฐœ๋ฅผ ์ƒ์„ฑ ryan์€ 80, charlotte๋Š” 90์œผ๋กœ ์ดˆ๊ธฐํ™” ๋˜์–ด์žˆ๋‹ค.
let ryan = Student(score: BehaviorSubject(value: 80))
let charlotte = Student(score: BehaviorSubject(value: 90))

let student = PublishSubject<Student>()

student
	.flatMapLatest({ (element: Student) -> Observable<Int> in
		element.score
	})
	.subscribe(onNext:{ (result: Int) in
		print(result)
  })
	.disposed(by: disposeBag)

student.onNext(ryan)
ryan.score.onNext(85)
// ์—ฌ๊ธฐ์„œ๋ถ€ํ„ฐ๋Š” ryan ์‹œํ€€์Šค๋Š” ๋ฌด์‹œ๋œ๋‹ค.
student.onNext(charlotte)

// ์–˜๋Š” ๋ˆ„๋ฝ๋จ
ryan.score.onNext(95)

charlotte.score.onNext(100)

๊ฒฐ๊ณผ

80
85
90
100

์œ„ ์ฝ”๋“œ๋ฅผ ๊ทธ๋ฆผ์œผ๋กœ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— ์ƒ์„ฑ๋œ ์‹œํ€€์Šค๊ฐ€ charlotte ์‹œํ€€์Šค์ด๊ธฐ ๋•Œ๋ฌธ์— ryan์˜ 95 ์—˜๋ฆฌ๋จผํŠธ๋Š” ๋ฌด์‹œ๋˜๋Š” ๋ชจ์Šต

image-20220306224605466

๊ฐ™์ด ๋ณด๋ฉด ์ข‹์€ ๋‚ด์šฉ

filter

์กฐ๊ฑด์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’๋งŒ ๋ฐฉ์ถœ

#1

Observable.of(1, 2, 3, 4, 5)
    .filter({ (element: Int) -> Bool in
      element < 3
    })
    .subscribe(onNext:{ (result: Int) in
      print(result)
    })
    .disposed(by: disposeBag)

๊ฒฐ๊ณผ

1
2

take

๋ช‡๊ฐœ์˜ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๊ฐ€์ ธ์˜ฌ์ง€ ์ •ํ•ด์ค€๋‹ค.

#1

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

๊ฒฐ๊ณผ

1
2

take(while:)

์กฐ๊ฑด์‹์ด false๊ฐ€ ๋˜๊ธฐ ์ „๊นŒ์ง€๋Š” ๋ฐฉ์ถœํ•˜๊ณ  false๊ฐ€ ๋˜๋ฉด ๋’ค๋กœ๋Š” ๋ฌด์‹œ

#1

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

๊ฒฐ๊ณผ

1
2
3
4

take(until:)

์–ด๋–ค ๋‹ค๋ฅธ ์˜ต์ €๋ฒ„๋ธ”์˜ ์‹คํ–‰์ด ์žˆ๊ธฐ์ „๊นŒ์ง€ ๊ฐ€์ ธ์˜ค๊ณ  ๊ทธ ๋’ค๋ก  ์ข…๋ฃŒ

#1

let subject = PublishSubject<Int>()
let subject2 = PublishSubject<Int>()

subject
	.take(until: subject2)
	.subscribe(onNext:{
  	print($0)
	})
	.disposed(by: disposeBag)

subject.onNext(1)
subject.onNext(2)
subject2.onNext(10)
subject.onNext(3)
subject2.onNext(20)
subject.onNext(4)

๊ฒฐ๊ณผ

1
2

startWith

Observable ์‹œํ€€์Šค ์•ž์— ๊ฐ’์„ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

#1

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

๊ฒฐ๊ณผ

0
1
2
3
4

merge

์ฐธ๊ณ : https://rhammer.tistory.com/309?category=649741

Observable ์‹œํ€€์Šค๋ฅผ ์ˆœ์„œ์—†์ด ํ•ฉ์ณ์ค€๋‹ค. 1๋ฒˆ 2๋ฒˆ Observable์ด ์žˆ๋‹ค๊ณ  ํ–ˆ์„ ๋•Œ 1๋ฒˆ ์‹œํ€€์Šค ๋ฐฉ์ถœ ํ•˜๊ณ  2๋ฒˆ ์‹œํ€€์Šค ๋ฐฉ์ถœ( ์ด๊ฑด concat()์ž„ )์ด ์•„๋‹ˆ๋ผ ์‹œํ€€์Šค์— ๋Œ€ํ•ด ์ˆœ์„œ๊ฐ€ ์—†์ด ๊ทธ๋ƒฅ ํ๋ฆ„๋Œ€๋กœ ํ•ฉ์ณ์ค€๋‹ค.

#1

let left = Observable.of("0", "1")
let right = Observable.of("zero", "one")

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

// ์ด๋ ‡๊ฒŒ ํ•ด๋„ ๋จ
//  source.merge()
Observable.merge(left, right)
	.subscribe(onNext:{
  	print($0)
	})
	.disposed(by: disposeBag)

๊ฒฐ๊ณผ(์ˆœ์„œ๋Š” ๋จผ์ € ์˜ค๋Š” ์ด๋ฒคํŠธ๋ถ€ํ„ฐ๋ผ ๊ทธ๋•Œ๋งˆ๋‹ค ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜จ๋‹ค.)

0
zero
1
one

merge์— ๋Œ€ํ•œ ๋ช‡๊ฐ€์ง€ ๊ทœ์น™

  • ๋‚ด๋ถ€ ์‹œํ€€์Šค๊ฐ€ ์ข…๋ฃŒ๋˜๋ฉด merge ์‹œํ€€์Šค๋„ ์ข…๋ฃŒ๋จ
  • ๋‚ด๋ถ€ ์‹œํ€€์Šค๊ฐ€ complete๋˜๋Š” ์‹œ์ ์€ ๋ชจ๋‘ ๋…๋ฆฝ์ 
  • ๋งŒ์•ฝ ๋‚ด๋ถ€ ์‹œํ€€์Šค์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๊ทธ ์ฆ‰์‹œ merge์‹œํ€€์Šค๋„ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋ฉฐ ์ข…๋ฃŒ๋จ

merge(maxConcurrent:)

์˜ˆ์ œ์—์„œ๋Š” 2๊ฐœ์˜ ์‹œํ€€์Šค๋งŒ ํ•ฉ์ณค์ง€๋งŒ 2๊ฐœ ์ด์ƒ์˜ ์‹œํ€€์Šค๋ฅผ ํ•ฉ์น ์ˆ˜๋„ ์žˆ๋‹ค.

merge(maxConcurrent:)์˜คํผ๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. maxConcurrent๊ฐœ์ˆ˜๋งŒํผ ํ•ฉ์นœ๋‹ค. ๋งŒ์•ฝ maxConcurrent๊ฐ€ ์ž‘์•„์„œ ํ•ฉ์ณ์ง€์ง€ ๋ชปํ•œ ์‹œํ€€์Šค๋Š” ํ์— ๋Œ€๊ธฐํ•˜๋‹ค๊ฐ€, ๋‚ด๋ถ€ ์‹œํ€€์Šค ์ค‘ ํ•˜๋‚˜๊ฐ€ complete๋˜๋ฉด ํ•ฉ์ณ์ง„๋‹ค.

withLatestFrom

์ฐธ๊ณ : https://rhammer.tistory.com/349?category=649741

๊ฐ๊ธฐ ๋‘๊ฐœ์˜ Observable์„ ํ•ฉ์„ฑํ•œ๋‹ค. ๋‹ค๋งŒ ์ฒซ๋ฒˆ์งธ Observable์˜ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•ด์•ผ ์ง€๋งŒ 2๊ฐœ๋ฅผ ๋ฌถ์–ด์„œ ์ตœ์ข… ์‹œํ€€์Šค๋กœ ์ „๋‹ฌํ•œ๋‹ค. ์ฒซ๋ฒˆ์งธ ์ด๋ฒคํŠธ๊ฐ€ ์—†๋‹ค๋ฉด ์ตœ์ข…์‹œํ€€์Šค๋กœ ์ „๋‹ฌx

#1

let inputNumber = PublishSubject<Int>()
let inputString = PublishSubject<String>()

inputNumber
	.withLatestFrom(inputString){ (lhs: Int, rhs: String) -> String in
  	"\(lhs):\(rhs)"
  }
	.subscribe(onNext:{
  	print($0)
	})
	.disposed(by: disposeBag)

// ๋ฐฉ์ถœx
inputNumber.onNext(1)
inputString.onNext("one")

// 2:one
inputNumber.onNext(2)
inputString.onNext("two")
inputString.onNext("three")
inputString.onNext("four")

// 3:four
inputNumber.onNext(3)

// 4:four
inputNumber.onNext(4)

// 5:four
inputNumber.onNext(5)

๊ฒฐ๊ณผ

2:one
3:four
4:four
5:four

#2

ํŠน์ • ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ, ํŠน์ • ์ƒํƒœ์˜ ์ตœ์‹ ๊ฐ’์„ ์–ป๊ณ ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹๋‹ค.

let button = PublishSubject<Void>()
let textField = PublishSubject<String>()

button
	.withLatestFrom(textField)
	.subscribe(onNext:{
  	print($0)
	})
	.disposed(by: disposeBag)

// textField์— ์ž…๋ ฅ์ค‘
textField.onNext("Par")
textField.onNext("Pari")
textField.onNext("Paris")

// ๋‹ค ์ž…๋ ฅํ•˜๊ณ  ๋ฒ„ํŠผ์„ ๋‘๋ฒˆ ํƒญ
button.onNext(())
button.onNext(())

๊ฒฐ๊ณผ

Paris
Paris

combineLatestF

์ฐธ๊ณ : https://rhammer.tistory.com/311?category=649741

2๊ฐœ์˜ OBservable์— ๊ฐ๊ฐ์˜ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์ตœ์‹  ์ด๋ฒคํŠธ๋ผ๋ฆฌ ๋ฌถ์–ด์„œ ์ตœ์ข… ์‹œํ€€์Šค์— ์ „๋‹ฌํ•œ๋‹ค.

๋‘ ์‹œํ€€์Šค๊ฐ€ ๊ฐ๊ฐ ์ตœ์ดˆ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ์•ผ๋งŒ ํ•ฉ์ณ์ง„ ์‹œํ€€์Šค์—์„œ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

#1

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

Observable
	.combineLatest(left, right) { lastLeft, lastRight in
		"\(lastLeft) \(lastRight)"
	}
	.subscribe(onNext:{
  	print($0)
	})
	.disposed(by: disposeBag)

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("RxSwift")

print("> Sending another value to left")
left.onNext("Have a good day,")

๊ฒฐ๊ณผ

> Sending a value to left
> Sending a value to right
Hello,  world
> Sending another value to right
Hello,  RxSwift
> Sending another value to left
Have a good day, RxSwift

๊ทธ๋ฆผ์œผ๋กœ ํ‘œํ˜„์•„๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

image-20220307231231372

#2

let choice: Observable<DateFormatter.Style> = Observable.of(.short, .long)
let dates = Observable.of(Date())

Observable.combineLatest(choice, dates){ (format: DateFormatter.Style, when: Date) -> String in
		let formatter = DateFormatter()
	  formatter.dateStyle = format

		return formatter.string(from: when)
	}
	.subscribe(onNext:{
  	print($0)
	})
	.disposed(by: disposeBag)

๊ฒฐ๊ณผ

2022/03/07
March 7, 2022

debounce & throttle

Reference

Rx์—์„œ๋Š” ์‚ฌ์šฉ์ž์˜ ์•ก์…˜์ด๋‚˜ ์ •์˜ํ•ด์ค€ ๊ฒƒ์— ๋”ฐ๋ผ observable์ด ๋ฐฉ์ถœ๋œ๋‹ค. ์ด ๋ง์€ ๋งŒ์•ฝ ๋™์‹œ๋‹ค๋ฐœ์ ์œผ๋กœ ์—ฌ๋Ÿฌ ์•ก์…˜์„ ์ทจํ•˜๋ฉด observable์ด ๋”ฐ๋‹ฅ๋”ฐ๋‹ฅ ๋ถ™์–ด์„œ ๋ฐฉ์ถœ๋œ๋‹ค๋Š” ์–˜๊ธฐ.

  • ๋ฒ„ํŠผ์„ ์—ฌ๋Ÿฌ๋ฒˆ ํด๋ฆญํ–ˆ์„ ๋•Œ
  • API ์ค‘๋ณต ํ˜ธ์ถœ์„ ๋ง‰์•„์ฃผ๋Š” ๋ณ„๋„ ์กฐ์น˜๋ฅผ ์ทจํ•ด์ค˜์•ผ ํ•˜๋Š”๋ฐ

debounce๋ž‘ throttle์„ ์‚ฌ์šฉํ•œ๋‹ค.

throttle

์ง€์ •๋œ ์‹œ๊ฐ„๋™์•ˆ Observable์ด ๋‚ด๋ณด๋‚ธ ์ฒซ๋ฒˆ์งธ ์—˜๋ฆฌ๋จผํŠธ์™€๋งˆ์ง€๋ง‰ ์—˜๋ฆฌ๋จผํŠธ(latest ์— ๋”ฐ๋ผ ๋‹ค๋ฆ„)๋ฅผ ๋‚ด๋ณด๋‚ด๋Š” Observable์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ด ์—ฐ์‚ฐ์ž๋Š” DueTime๋ณด๋‹ค ์งง์€ ์‹œ๊ฐ„์— ๋‘๊ฐœ์˜ ์š”์†Œ๊ฐ€ ๋‚ด๋ณด๋‚ด์ง€์ง€ ์•Š๋„๋ก ํ•œ๋‹ค. (์ฐธ๊ณ : ๋ฐฉ์ถœํ•˜๋ฉด throttle ํƒ€์ด๋จธ ํ˜๋Ÿฌ๊ฐ)

์ง€์ •๋œ ์‹œ๊ฐ„์•ˆ์— ์ˆ˜๋งŽ์€ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ 2๊ฐœ ์ด์ƒ ์š”์†Œ๊ฐ€ ๋ฐฉ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์–˜๊ธฐ์ž„

throttle์€ ์—ฌ๋Ÿฌ ์š”์ฒญ์ค‘์—์„œ ๊ฐ’์„ ๋”ฑ ํ•œ๋ฒˆ๋งŒ ๋ณด๋‚ผ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. tableView infinity scroll์— ๋งŽ์ด ์‚ฌ์šฉ๋œ๋‹ค. ๋ฏธ์นœ๋“ฏ์ด ์Šคํฌ๋กค๋ง ํ•˜๋ฉด ์š”์ฒญ์ด ์—ฌ๋Ÿฌ๋ฒˆ ์ด๋ฃจ์–ด ์งˆ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์š”์ฒญ์ด ํ•œ๋ฒˆ ์ด๋ฃจ์–ด์ง€๋ฉด throttle๋กœ ๋”œ๋ ˆ์ด๋ฅผ ์ค˜์„œ ์˜๋„ํ•˜์ง€ ์•Š์€ ์š”์ฒญ์„ ๋ง‰์„ ์ˆ˜ ์žˆ๋‹ค. ๋˜๋Š” button์—๋„ ์‚ฌ์šฉ๋˜๋Š”๋ฐ ๋ฏธ์นœ๋“ฏ์ด button์„ ๋ˆ„๋ฅด๋ฉด api call์„ ์—ฌ๋Ÿฌ๋ฒˆ ํ•  ์ˆ˜๋„ ์žˆ์œผ๋‹ˆ throttle๋กœ ๋ง‰๋Š”๋‹ค. (chattering๋ฐœ์ƒ์— delay ์ฃผ๋Š”๊ฑฐ๋ž‘ ๋˜‘๊ฐ™๋‹ค.)

#1

latest๊ฐ€ true์ธ ๊ฒฝ์šฐ

Observable<Int>
    .interval(.seconds(2), scheduler: MainScheduler.instance)
    .take(6)
    .throttle(.seconds(5), scheduler: MainScheduler.instance)
    .subscribe(onNext:{
      print($0)
    })
    .disposed(by: disposeBag)

๊ฒฐ๊ณผ

0
2
5

latest๊ฐ€ true์ธ ๊ฒฝ์šฐ ์ง€์ •๋œ ์‹œ๊ฐ„์ด ์ง€๋‚œ ์ดํ›„ ๋งˆ์ง€๋ง‰์— ๋ฐฉ์ถœ๋œ ์š”์†Œ๋„ ๋ฐฉ์ถœํ•ด์ค€๋‹ค. ๋”ฐ๋ผ์„œ throttle ์‹œ๊ฐ„์ด 5์ดˆ ํ˜๋Ÿฌ๊ฐ”์„ ๋•Œ 4์ดˆ์— ๋ฐฉ์ถœ๋œ 2๊ฐ€ ๋งˆ์ง€๋ง‰ ์—˜๋ฆฌ๋จผํŠธ์ด๋ฏ€๋กœ 2๊ฐ€ ๋ฐฉ์ถœ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‹ค์‹œ throttle์€ 0์ดˆ๋ถ€ํ„ฐ ์ดˆ๋ฅผ ์„ผ๋‹ค. 5์ดˆ๊ฐ€ ์ง€๋‚˜๊ณ  10์ดˆ์— ๋ฐฉ์ถœ๋œ 5 ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ฐฉ์ถœํ•œ๋‹ค.

๊ทธ๋ฆผ์œผ๋กœ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

image-20220308235408766

#2

latest๊ฐ€ false์ธ ๊ฒฝ์šฐ

Observable<Int>
    .interval(.seconds(2), scheduler: MainScheduler.instance)
    .take(6)
		.throttle(.seconds(5), latest: false, scheduler: MainScheduler.instance)
    .subscribe(onNext:{
      print($0)
    })
    .disposed(by: disposeBag)

๊ฒฐ๊ณผ

0
3

latest๊ฐ€ false์ธ ๊ฒฝ์šฐ ์ง€์ •๋œ ์‹œ๊ฐ„๋™์•ˆ์€ ์–ด๋– ํ•œ ๊ฐ’๋„ ๋ฐฉ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค. true์ผ๋•Œ์™€๋Š” ๋‹ค๋ฅด๊ฒŒ ๋งˆ์ง€๋ง‰์— ๋ฐฉ์ถœ๋œ ๊ฐ’๋„ ๋ฐฉ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค.

๊ทธ๋ฆผ์œผ๋กœ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

image-20220308235656950

debounce

์ง€์ •๋œ ์‹œ๊ฐ„๊ฐ„๊ฒฉ ๋‚ด์— ๋งˆ์ง€๋ง‰ ํ•˜๋‚˜์˜ source ์ด๋ฒคํŠธ๋ฅผ ์ตœ์ข… ์‹œํ€€์Šค์— ๋ฐฉ์ถœํ•œ๋‹ค. source ์ด๋ฒคํŠธ๊ฐ€ ๋ฐฉ์ถœ๋  ๋•Œ๋งˆ๋‹ค ํƒ€์ด๋จธ๋Š” ์ดˆ๊ธฐํ™”๋œ๋‹ค.

#1

Observable<Int>
    .interval(.seconds(2), scheduler: MainScheduler.instance)
    .take(3)
    .debounce(.seconds(1), scheduler: MainScheduler.instance)
    .subscribe(onNext: {
      print($0)
    })
    .disposed(by: disposeBag)

๊ฒฐ๊ณผ

0
1
2

์‹œ๊ฐ„ ๊ฐ’์„ ๋ณด๋ฉด 2์ดˆ๋งˆ๋‹ค timer๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  debounce ์—์„œ 1์ดˆ๋กœ ์„ค์ •ํ–ˆ๊ธฐ์— 1์ดˆ ๋‚ด์— ๋‹ค๋ฅธ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ 1์ดˆ๋’ค debounce๋œ Observable์— ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

๊ทธ๋ฆผ์œผ๋กœ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

image-20220309003152748

๋งŒ์•ฝ deobunce์— 2๋ณด๋‹ค ํฐ๊ฐ’(interval์—์„œ ์„ค์ •ํ•œ ์‹œ๊ฐ„๊ฐ’๋ณด๋‹ค ํฐ๊ฐ’)์„ ์„ค์ •ํ•˜๋ฉด ์•„๋ฌด๊ฒƒ๋„ ๋ฐฉ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค.

Observable<Int>
    .interval(.seconds(2), scheduler: MainScheduler.instance)
    .take(3)
// ๋งŒ์•ฝ deobunce์— 2๋ณด๋‹ค ํฐ๊ฐ’์„ ์„ค์ •ํ•˜๋ฉด ์•„๋ฌด๊ฒƒ๋„ ๋ฐฉ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค.
    .debounce(.seconds(3), scheduler: MainScheduler.instance)
    .subscribe(onNext: {
      print($0)
    })
    .disposed(by: disposeBag)

๊ฒฐ๊ณผ

share

์ฐธ๊ณ : https://jusung.github.io/shareReplay/

share๋Š” ๋™์ผํ•œ ์—ฌ๋Ÿฌ Observable์— ๋Œ€ํ•ด ํ•˜๋‚˜์˜ ์‹œํ€€์Šค๋งŒ ์ƒ์„ฑํ•ด์ค€๋‹ค. ์ฆ‰, ๋ฆฌ์†Œ์Šค ๋น„์šฉ์„ ์ค„์—ฌ์ค€๋‹ค.

์šฐ์„  share๋ฅผ ์„ค๋ช…ํ•˜๊ธฐ ์ „์— Observable์˜ ํŠน์ง•ํ•˜๋‚˜๋ฅผ ๊ธฐ์–ตํ•˜์ž. Observable์€ subscribe๊ฐ€ ํ˜ธ์ถœ๋˜๊ธฐ ์ „๊นŒ์ง€๋Š” ์‹œํ€€์Šค๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š”๋‹ค.

๋‹ค์Œ ์ฝ”๋“œ๋Š” share๋ฅผ ์ ์šฉํ•˜์ง€ ์•Š์€ ์ฝ”๋“œ์ด๋‹ค.

class ViewController: UIViewController{
  let disposeBag = DisposeBag()
  @IBOutlet weak var label: UILabel!
  @IBOutlet weak var button: UIButton!
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    let rx = Observable.of(100).debug("##")
      
    let result = button.rx.tap
      .flatMap{rx}
//      .share()
    result
      .map{$0>0}
      .bind(to: button.rx.isHidden)
      .disposed(by: disposeBag)
      
    
    result
      .map { "\($0)" }
      .bind(to: label.rx.text)
      .disposed(by: disposeBag)
  }
}

๊ฒฐ๊ณผ

2022-03-09 11:22:22.674: ## -> subscribed
2022-03-09 11:22:22.676: ## -> Event next(100)
2022-03-09 11:22:22.677: ## -> Event completed
2022-03-09 11:22:22.677: ## -> isDisposed
2022-03-09 11:22:22.677: ## -> subscribed
2022-03-09 11:22:22.677: ## -> Event next(100)
2022-03-09 11:22:22.677: ## -> Event completed
2022-03-09 11:22:22.678: ## -> isDisposed

๋ฌธ์ œ๊ฐ€ ๋ญ๋ƒ๋ฉด ๋™์ผํ•œ ์‹œํ€€์Šค๊ฐ€ subscribe ๊ฐฏ์ˆ˜๋งŒํผ ์ƒ์„ฑ๋˜์—ˆ๋‹ค. 2๊ฐœ๋Š” ์ตœ์ข… ๊ฒฐ๊ณผ๋Š” ๋‹ค๋ฅผ์ง€ ๋ชฐ๋ผ๋„ observable์„ ํ†ตํ•ด ๋™์ผํ•˜๊ฒŒ next(100)์„ ๋ฐฉ์ถœํ•œ ๊ฐ’์„ ์‚ฌ์šฉํ•œ๋‹ค. next(100)์ด ๋‘๋ฒˆ ๋ฐœ์ƒํ–ˆ๋‹ค. ์ฆ‰, ์‹œํ€€์Šค๊ฐ€ 2๊ฐœ๋ผ๋Š” ๋œป

๊ทธ๋ฆผ์œผ๋กœ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

image-20220309112328297

์ฐธ๊ณ ๋กœ bind(to:)๋ฅผ ์ ์ง€ ์•Š๊ณ  subscrbie{...} ๋ฅผ ์ ์—ˆ๋Š”๋ฐ bind(to:)๋Š” subscribe์˜ ๋ณ„์นญ(alias)์œผ๋กœ subscrbie๋ฅผ ํ˜ธ์ถœํ•œ ๊ฒƒ๊ณผ ๋™์ผํ•˜๋‹ค.

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

class ViewController: UIViewController{
  let disposeBag = DisposeBag()
  @IBOutlet weak var label: UILabel!
  @IBOutlet weak var button: UIButton!
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    let rx = Observable.of(100).debug("##")
      
    let result = button.rx.tap
      .flatMap{rx}
      .share()
    result
      .map{$0>0}
      .bind(to: button.rx.isHidden)
      .disposed(by: disposeBag)
      
    
    result
      .map { "\($0)" }
      .bind(to: label.rx.text)
      .disposed(by: disposeBag)
  }
}

๊ฒฐ๊ณผ

๊ทธ๋ฆผ์œผ๋กœ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

image-20220309112458103

share()๋Š” subscribe()๊ฐ€ ์ฒ˜์Œ ํ˜ธ์ถœ๋  ๋•Œ (SubscriptoinํšŸ์ˆ˜๊ฐ€ 0 -> 1 ์ผ๋•Œ)๋งŒ Subscription์„ ์ƒ์„ฑํ•˜๊ณ , ์ดํ›„ ๋‘๋ฒˆ์งธ ์„ธ๋ฒˆ์งธ๋กœ subscribe()๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด ์ƒˆ๋กœ์šด Subscription์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ ๋Œ€์‹  ์ด๋ฏธ ๋งŒ๋“ค์–ด์ง„ Subscription์„ ์ดํ›„ subscribe()๋ฅผ ํ˜ธ์ถœํ•œ ๊ณณ์— ๊ณต์œ ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.

๋งŒ์•ฝ share()์— subscribe()ํ•œ Subscription์ด ๋ชจ๋‘ disposed ๋˜๋ฉด share()๋Š” ๊ณต์œ ํ–ˆ๋˜ Subscription์„ dispose ์‹œํ‚จ๋‹ค.

์ดํ›„ ๋‹ค๋ฅธ subscribe()๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด share()๋Š” ์ƒˆ๋กœ์šด Subscription์„ ์ƒ์„ฑํ•œ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— share()๋Š” completed ๋˜์ง€ ์•Š๋Š” Observable์— ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•˜๋‹ค. ํ˜น์€ ๊ณต์œ ํ•˜๋Š” ์‹œํ€€์Šค๊ฐ€ completed ๋œ ํ›„ ์ƒˆ๋กœ์šด Observable์ด ์ƒ์„ฑ๋˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ™•์‹ ํ•  ๋•Œ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค.

์˜ˆ์ œ๋ฅผ playground๊ฐ€ ์•„๋‹Œ xcodeproj ์—์„œ ํ•œ ์ด์œ ๋„ ์ด์™€ ๊ฐ™์€ ๋งฅ๋ฝ์ด๋‹ค playground์—์„œ ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด 2๋ฒˆ์งธ ์‹œํ€€์Šค๊ฐ€ ์ˆ˜ํ–‰๋˜๊ธฐ ์ „์— completed ๋˜๊ธฐ ๋•Œ๋ฌธ์— share ์˜ˆ์ œ๋ฅผ ๋ณด์—ฌ์ฃผ๊ธฐ์— ์–ด๋ ค์›€์ด ์žˆ๋‹ค.

let observable = Observable.of(1)
	.debug("### ")
	.share()


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

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

๊ฒฐ๊ณผ

2022-03-09 11:16:26.771: ###  -> subscribed
2022-03-09 11:16:26.771: ###  -> Event next(1)
2
2022-03-09 11:16:26.772: ###  -> Event completed
2022-03-09 11:16:26.772: ###  -> isDisposed
2022-03-09 11:16:26.814: ###  -> subscribed
2022-03-09 11:16:26.815: ###  -> Event next(1)
3
2022-03-09 11:16:26.815: ###  -> Event completed
2022-03-09 11:16:26.815: ###  -> isDisposed

๋ฌผ๋ก  ์ด๋ ‡๊ฒŒ ํ•ด๋„ ๋˜์ง€๋งŒ ์œ„์— ์ฒ˜์Œ ์˜ˆ์ œ๊ฐ€ ๋” ์ง๊ด€์ ์ด๋‹ค.

let observable = PublishSubject<Int>()
  
let reulst = observable.debug().share()

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

reulst
	.map{ $0 * 3 }
	.subscribe(onNext:{
  	print($0)
	})
	.disposed(by: disposeBag)

observable.onNext(1)

๊ฒฐ๊ณผ

2022-03-09 11:30:59.207: OperatorPractice.playground:643 (__lldb_expr_183) -> subscribed
2022-03-09 11:30:59.207: OperatorPractice.playground:643 (__lldb_expr_183) -> Event next(1)
2
3