Filtering

๐Ÿšฟ Filtering Operators โ€” ํ•„์š”ํ•œ ์ด๋ฒคํŠธ๋งŒ โ€˜๊ฑธ๋Ÿฌ๋‚ด๊ธฐโ€™

โ€œSignal-to-noise ratio๋ฅผ ๋†’์—ฌ๋ผ!โ€

Filtering ๊ณ„์—ด ์˜คํผ๋ ˆ์ดํ„ฐ๋Š” Observable ์ŠคํŠธ๋ฆผ์—์„œ ํŠน์ • ์กฐ๊ฑด์— ๋งž๋Š” ๊ฐ’์ด๋‚˜ ์ด๋ฒคํŠธ๋งŒ ํ†ต๊ณผ์‹œํ‚ค๊ณ  ๋‚˜๋จธ์ง€๋Š” ๋ฌด์‹œํ•ฉ๋‹ˆ๋‹ค. UI ์ž…๋ ฅ ๋””๋ฐ”์šด์Šค, ์ด๋ฒคํŠธ ๋ฌด์‹œ, ์ค‘๋ณต ์ œ๊ฑฐ ๋“ฑ ํ”ํžˆ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.


1๏ธโƒฃ ๋Œ€ํ‘œ Filtering ์˜คํผ๋ ˆ์ดํ„ฐ ์š”์•ฝ

์˜คํผ๋ ˆ์ดํ„ฐ
์„ค๋ช…
์‹œ๊ทธ๋‹ˆ์ฒ˜ ์š”์•ฝ

filter

์กฐ๊ฑด์— ๋งž๋Š” ๊ฐ’๋งŒ ํ†ต๊ณผ

(Element) -> Bool

take / takeLast

์ฒ˜์Œ(N) / ๋งˆ์ง€๋ง‰(N)๊ฐœ ๊ฐ€์ ธ์˜ค๊ธฐ

Int

skip / skipLast

์ฒ˜์Œ(N) / ๋งˆ์ง€๋ง‰(N)๊ฐœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ

Int

takeWhile / skipWhile

์กฐ๊ฑด true ๋™์•ˆ ๊ฐ€์ ธ์˜ค๊ธฐ / ๊ฑด๋„ˆ๋›ฐ๊ธฐ

(Element) -> Bool

distinctUntilChanged

๋™์ผ ์—ฐ์† ๊ฐ’ ์ œ๊ฑฐ

== ๊ธฐ์ค€ (Equatable)

elementAt

ํŠน์ • ์ธ๋ฑ์Šค ๊ฐ’ 1๊ฐœ

Int

ignoreElements

.completed๋งŒ ์ „๋‹ฌ (๊ฐ’ ๋ฌด์‹œ)

โ€”

Time ๊ธฐ๋ฐ˜(debounce, throttle)์€ ๋ณ„๋„ ๋ฌธ์„œ timeBased.md์—์„œ ๋‹ค๋ฃน๋‹ˆ๋‹ค.


2๏ธโƒฃ ์‹ค์ „ ์Šค๋‹ˆํŽซ

A. ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ํ™œ์„ฑํ™” โ€” ๊ณต๋ฐฑ ์ œ๊ฑฐ ํ›„ ๋น„์–ด์žˆ์ง€ ์•Š์€์ง€ ์ฒดํฌ

textField.rx.text.orEmpty
    .map { $0.trimmingCharacters(in: .whitespaces) }
    .filter { !$0.isEmpty }
    .bind(to: viewModel.username)

B. ์—ฐ์† ํƒญ ๋ฐฉ์ง€ โ€” distinctUntilChanged()

button.rx.tap
    .map { Date() }
    .distinctUntilChanged { prev, next in next.timeIntervalSince(prev) < 0.3 }
    .subscribe(onNext: performAction)

C. ์ฒ˜์Œ 3๊ฐœ ์ƒ˜ํ”Œ๋งŒ ํ”„๋ฆฌ๋ทฐ ํ›„ ์ž๋™ ์ข…๋ฃŒ

photoStream
    .take(3)
    .subscribe(onNext: showSample,
               onCompleted: { print("sample end") })

3๏ธโƒฃ Operator ์—ฐ์‚ฐ ์ˆœ์„œ ์ฃผ์˜

  • take(1).skip(1) โžก๏ธ ๊ฒฐ๊ณผ 0๊ฐœ (take๊ฐ€ ๋จผ์ € ์‹คํ–‰)

  • skip(1).take(1) โžก๏ธ ๋‘ ๋ฒˆ์งธ ์š”์†Œ 1๊ฐœ ์ „๋‹ฌ

  • ์ฒด์ธ ์ˆœ์„œ๋ฅผ ๋ฐ”๊ฟ€ ๋•Œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋กœ ๊ธฐ๋Œ€ ๊ฐ’ ํ™•์ธ ํ•„์š”


4๏ธโƒฃ Error & Completion ์ „ํŒŒ ๊ทœ์น™

  • Filtering ์˜คํผ๋ ˆ์ดํ„ฐ๋Š” onNext๋งŒ ํ•„ํ„ฐ๋ง, onError / onCompleted๋Š” ๊ทธ๋Œ€๋กœ ์ „ํŒŒ.

  • ignoreElements๋Š” onError๋„ ๋ฌด์‹œํ•˜์ง€ ์•Š์Œ โ€” ์—๋Ÿฌ๋Š” ์ƒ์œ„๋กœ ์ „๋‹ฌ๋˜์–ด์•ผ ๋””๋ฒ„๊น… ์šฉ์ด.


5๏ธโƒฃ Performance & Memory Tips

  • ํฐ ๋ฐฐ์—ด์„ ๋ฐฐ์ถœํ•˜๋Š” ์ŠคํŠธ๋ฆผ์—์„œ filter ํ›„ map ์ˆœ์„œ๋กœ ์ตœ์ ํ™” (๋ถˆํ•„์š”ํ•œ ๋งคํ•‘ ์ค„์ด๊ธฐ).

  • distinctUntilChanged ์ปค์Šคํ…€ ๋น„๊ต๋Š” ๊ฐ’ ํƒ€์ž…์ผ ๋•Œ ๋น„์šฉ ๊ณ ๋ ค.


6๏ธโƒฃ Mini Quiz

  1. skipUntil(trigger)์™€ takeUntil(trigger) ์ฐจ์ด๋ฅผ ์„ค๋ช…ํ•˜๋ผ.

  2. distinctUntilChanged๊ฐ€ Equatable์ด ์•„๋‹Œ ํƒ€์ž…์—์„œ ๋™์ž‘ํ•˜๋ ค๋ฉด?

  3. takeLast(1)๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ์€?

Answers
  1. skipUntil: Trigger Observable์ด ์ฒซ ์ด๋ฒคํŠธ๋ฅผ ๋ฐฉ์ถœํ•  ๋•Œ๊นŒ์ง€ ์›๋ณธ ๊ฐ’์„ ๋ฌด์‹œ, ์ดํ›„ ๋ชจ๋‘ ํ†ต๊ณผ. takeUntil: Trigger๊ฐ€ ๊ฐ’ ๋ฐฉ์ถœํ•˜๋Š” ์ˆœ๊ฐ„ ๊ทธ ์ดํ›„ ์›๋ณธ ์ŠคํŠธ๋ฆผ์„ ์™„๋ฃŒ์‹œ์ผœ ๋” ์ด์ƒ ํ†ต๊ณผํ•˜์ง€ ์•Š์Œ.

  2. ํด๋กœ์ € ๋ฒ„์ „์„ ์‚ฌ์šฉ: distinctUntilChanged { prev, next in /* ๋น„๊ต์‹ */ }.

  3. takeLast๋Š” ๋ฒ„ํผ์— ์ตœ๋Œ€ N๊ฐœ ์š”์†Œ๋ฅผ ์ €์žฅํ•˜๋ฏ€๋กœ, N์ด ์ž‘์•„๋„ ๋ฉ”๋ชจ๋ฆฌ ๋ฒ„ํผ๊ฐ€ ์กด์žฌ; ๋Œ€์šฉ๋Ÿ‰ ์ŠคํŠธ๋ฆผ์—์„œ ํฐ N์ด๋ฉด ๋ฉ”๋ชจ๋ฆฌ ์ฆ๊ฐ€.


๋‹ค์Œ โ–ถ๏ธ transforming ๋กœ ์ด๋™ํ•ด map, flatMap, scan ๋“ฑ ๋ณ€ํ™˜ ์˜คํผ๋ ˆ์ดํ„ฐ๋ฅผ ํ•™์Šตํ•ฉ๋‹ˆ๋‹ค. ๐Ÿš€

Last updated