Transforming

๐Ÿ”„ Transforming Operators โ€” ์ŠคํŠธ๋ฆผ์„ โ€˜๋ณ€ํ˜•โ€™ํ•˜๋Š” ๋งˆ๋ฒ•

โ€œ๋ฐ์ดํ„ฐ๋ฅผ ์›ํ•˜๋Š” ๋ชจ์Šต์œผ๋กœ ๊ฐ€๊ณตํ•˜๋ผ.โ€

Transforming ๊ณ„์—ด ์˜คํผ๋ ˆ์ดํ„ฐ๋Š” Observable์˜ ๊ฐ’ ๊ตฌ์กฐยทํƒ€์ž…ยท๊ฐœ์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•˜์—ฌ ๋‹ค์Œ ๋‹จ๊ณ„์—์„œ ํ™œ์šฉํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ํŠนํžˆ mapยทflatMapยทscan์€ Rx์˜ ์‚ผ๋Œ€์žฅ์ด๋ผ ๋ถˆ๋ฆด ๋งŒํผ ์ž์ฃผ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.


1๏ธโƒฃ ํ•ต์‹ฌ ์˜คํผ๋ ˆ์ดํ„ฐ ์š”์•ฝ

์˜คํผ๋ ˆ์ดํ„ฐ
์„ค๋ช…
๋Œ€ํ‘œ ์‹œ๊ทธ๋‹ˆ์ฒ˜

map

์š”์†Œ๋ฅผ 1:1 ๋ณ€ํ™˜

(Element) -> R

compactMap

nil ํ•„ํ„ฐ๋ง & ๋ณ€ํ™˜

(Element) -> R?

flatMap

์š”์†Œ๋ฅผ Observable๋กœ ๋ณ€ํ™˜ ํ›„ ๋ณ‘ํ•ฉ

(Element) -> Observable<R>

flatMapLatest

๊ฐ€์žฅ ์ตœ์‹  ๋‚ด๋ถ€ Observable๋งŒ ๊ตฌ๋…(switch)

same

flatMapFirst

์ฒซ ๋‚ด๋ถ€ ์ŠคํŠธ๋ฆผ ์ง€์†, ์ดํ›„ ๋ฌด์‹œ

same

concatMap

์ด์ „ ๋‚ด๋ถ€ Observable ์™„๋ฃŒ ํ›„ ๋‹ค์Œ ์‹คํ–‰

same

scan

๋ˆ„์ (accumulate) reduce

(Accumulator, Element) -> Accumulator

buffer

์ฃผ๊ธฐยท๊ฐœ์ˆ˜ ๋‹จ์œ„ ๋ฐฐ์—ด๋กœ ๋ฌถ๊ธฐ

timeSpan,count,scheduler

materialize/dematerialize

Event โ†”๏ธŽ Element ๋ณ€ํ™˜

-


2๏ธโƒฃ ์‹ค์ „ ์˜ˆ์ œ

A. map โ€” JSON โ†’ Model ํŒŒ์‹ฑ

urlSession.rx.data(request: req)
    .map { try JSONDecoder().decode(User.self, from: $0) }
    .subscribe(onNext: showUser)

B. flatMapLatest โ€” ํ…์ŠคํŠธ ๊ฒ€์ƒ‰ ์ž๋™์™„์„ฑ

searchBar.rx.text.orEmpty
    .debounce(.milliseconds(300), scheduler: MainScheduler.instance)
    .flatMapLatest(api.search) // ์ƒˆ๋กœ์šด ํ‚ค์›Œ๋“œ ์ž…๋ ฅ ์‹œ ์ด์ „ ์š”์ฒญ ์ทจ์†Œ
    .bind(to: tableView.rx.items(...))

C. scan โ€” ์นด์šดํ„ฐ ๋ˆ„์ 

button.rx.tap
    .map { _ in 1 }
    .scan(0, accumulator: +)
    .subscribe(onNext: counterLabel.rx.text)

D. buffer โ€” 3๊ฐœ์”ฉ ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ

sensorStream
    .buffer(timeSpan: .seconds(1), count: 3, scheduler: MainScheduler.instance)
    .filter { !$0.isEmpty }
    .subscribe(onNext: uploadBatch)

3๏ธโƒฃ flatMap ํŒจ๋ฐ€๋ฆฌ ์„ ํƒ ๊ฐ€์ด๋“œ

์ƒํ™ฉ
๊ถŒ์žฅ ์˜คํผ๋ ˆ์ดํ„ฐ
์ด์œ 

๋„คํŠธ์›Œํฌ ์š”์ฒญ, ์ด์ „ ๊ฒฐ๊ณผ ๋ฌด์‹œ

flatMapLatest

์ตœ์‹  ์š”์ฒญ๋งŒ ์œ ์ง€ (์ทจ์†Œ)

์ฒซ ์š”์ฒญ ๊ณ ์ •, ์ค‘๋ณต ๋ฌด์‹œ

flatMapFirst

๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ๋”๋ธ” ํƒญ ๋ฐฉ์ง€

์ˆœ์„œ ๋ณด์žฅ, ์ง๋ ฌ ์‹คํ–‰

concatMap

ํŒŒ์ผ ์—…๋กœ๋“œ ์ฐจ๋ก€๋Œ€๋กœ

๋ชจ๋“  ๋‚ด๋ถ€ ์ŠคํŠธ๋ฆผ ๋ณ‘ํ•ฉ

flatMap

์ด๋ฏธ์ง€ ํ”„๋ฆฌ๋กœ๋“œ ๋™์‹œ ์‹คํ–‰


4๏ธโƒฃ ์„ฑ๋Šฅ & ์—๋Ÿฌ ์ „๋žต

  • flatMap์—์„œ ๋‚ด๋ถ€ Observable์ด ๋ฌดํ•œ ์ŠคํŠธ๋ฆผ์ด๋ฉด dispose ์‹œ์  ๊ด€๋ฆฌ ํ•„์š”.

  • scan ์ดˆ๊ธฐ๊ฐ’ ์„ค์ •์ด ์ค‘์š” โ€” ๋ถˆ๋ณ€ ๊ฐ์ฒด๋ผ๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ์œ„ํ—˜ ๋‚ฎ์Œ.

  • buffer๋กœ ํฐ ๋ฐฐ์—ด ์ƒ์„ฑ ์‹œ ๋ฉ”๋ชจ๋ฆฌ ํ”ผํฌ ๊ฐ€๋Šฅ, window(Observable) ๋Œ€์•ˆ.


5๏ธโƒฃ Transform + Scheduler ์˜ˆ์‹œ

images
    .flatMap { UIImageJPEGRepresentation($0, 0.8) ?? Data() } // ๋ณ€ํ™˜
    .observe(on: ConcurrentDispatchQueueScheduler(qos: .utility)) // IO
    .scan(Data(), +) // ๋ˆ„์  ์••์ถ•
    .observe(on: MainScheduler.instance)
    .subscribe(onNext: updateProgress)

6๏ธโƒฃ Mini Quiz

  1. flatMapLatest ๋‚ด๋ถ€์—์„œ .share()๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์–ด๋–ค ํšจ๊ณผ?

  2. scan์œผ๋กœ ๋ˆ„์  ํ•ฉ์„ ๊ตฌํ•  ๋•Œ ๋ฉ”๋ชจ๋ฆฌ ์ฆ๊ฐ€๋ฅผ ๋ฐฉ์ง€ํ•  ๋ฐฉ๋ฒ•์€?

  3. buffer(timeSpan:.seconds(5), count: Int.max, ...) ์„ค์ • ์‹œ ์ฃผ์˜์ ?

Answers
  1. ์—ฌ๋Ÿฌ ๊ตฌ๋…์ž๊ฐ€ flatMapLatest ๊ฒฐ๊ณผ๋ฅผ ๊ณต์œ ํ•˜๋˜, ์ตœ์‹  ๋‚ด๋ถ€ ์ŠคํŠธ๋ฆผ 1๊ฐœ๋กœ ํ•œ์ • โ€” ๋„คํŠธ์›Œํฌ ์บ์‹ฑ ํšจ๊ณผ & ๋ฆฌ์†Œ์Šค ์ ˆ์•ฝ.

  2. ๋ˆ„์ ๊ฐ’์ด ๊ณ„์† ์ปค์งˆ ๊ฒฝ์šฐ map { $0 % 10 } ์ฒ˜๋Ÿผ ํฌ๊ธฐ๋ฅผ ์ œํ•œํ•˜๊ฑฐ๋‚˜, reduce๋กœ ์ตœ์ข…๊ฐ’๋งŒ ํ•„์š”ํ•  ๋•Œ ์ŠคํŠธ๋ฆผ ์™„๋ฃŒ ํ›„ ์ „๋‹ฌ.

  3. count๊ฐ€ ๋ฌดํ•œ๋Œ€์ด๋ฏ€๋กœ 5์ดˆ ๋™์•ˆ ๋ฐœ์ƒํ•œ ๋ชจ๋“  ์ด๋ฒคํŠธ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ๋ฒ„ํผ; ์ด๋ฒคํŠธ ํญ์ฃผ ์‹œ ๋ฉ”๋ชจ๋ฆฌ ๊ธ‰์ฆ ์œ„ํ—˜ โ€” ์ ์ ˆํ•œ count ์„ค์ • ํ•„์š”.


๋‹ค์Œ โ–ถ๏ธ combining ๋กœ ์ด๋™ํ•ด merge, combineLatest, zip ๋“ฑ์„ ํ•™์Šตํ•ฉ์‹œ๋‹ค. ๐Ÿš€

Last updated