<h1><center> Combine Chapter 01 - Hello Combine </center></h1> ###### tags: `๐Ÿ’ป TIL` ###### date: `2024-04-1617:21:33.284Z` > [color=#724cd1][name=๋ฐ๋ฆญ] > [Hello, Combine!](https://www.kodeco.com/books/combine-asynchronous-programming-with-swift/v4.0/chapters/1-hello-combine) > [Publisher](https://developer.apple.com/documentation/combine/publisher) > [Subscriber](https://developer.apple.com/documentation/combine/subscriber) # ๊ฐœ์š” > Kodeco์˜ Combine: Asynchronous Programming With Swift๋ฅผ ๋ณด๋ฉด์„œ ํ•™์Šตํ•˜์ž. ## Hello, Combine Combine ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์„ ์–ธํ˜• ์ ‘๊ทผ ๋ฐฉ๋ฒ•์œผ๋กœ ์•ฑ์—์„œ ํ•„์š”ํ•œ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, ์—ฌ๋Ÿฌ ๊ฐœ์˜ Delegate ์ฝœ๋ฐฑ์ด๋‚˜ Completion Handler๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  ์ด๋ฒคํŠธ๋ฅผ ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์Šค ์ฒด์ธ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ์ฒด์ธ์˜ ๊ฐ Part๋Š” ์ด์ „ ๋‹จ๊ณ„์—์„œ ๋ฐ›์€ Element๋“ค์— ๋Œ€ํ•ด ๋ณ„๋„์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” Combine Operator์ด๋‹ค. ## Asynchronous Programming Single Thread ์–ธ์–ด์—์„œ ํ”„๋กœ๊ทธ๋žจ์€ ํ•œ ์ค„์”ฉ ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค.(ex: javascript) ```swift // begin var name = "Derrick" print(name) name += " Kim" print(name) // End ``` > Single Thread๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ์˜ ํ˜„์žฌ ์ƒํƒœ๋ฅผ ํ•ญ์ƒ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. **๋‹ค์ค‘ ์Šค๋ ˆ๋“œ** ```swift --- Thread 1 --- begin var name = "Tom" print(name) --- Thread 2 --- name = "Billy Bob" --- Thread 1 --- name += " Harding" print(name) end ``` > ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๋กœ name์ด๋ž€ ๊ณต์œ ์ž์›์— ์ ‘๊ทผํ•  ๊ฒฝ์šฐ ํ•ญ์ƒ ๊ฐ™์€ ๊ฐ’์„ ๋ณด์žฅํ•  ์ˆ˜ ์—†๋‹ค. ## Foundation and UIKit / AppKit NSThread์™€ ๊ฐ™์€ ์ €์ˆ˜์ค€ API๋ถ€ํ„ฐ Swift์˜ ํ˜„๋Œ€์  ๋™์‹œ์„ฑ์„ ํ™œ์šฉํ•œ async/await ๊ตฌ์กฐ๊นŒ์ง€ ๋‹ค์–‘ํ•œ API๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. **Notification Center**: ์‚ฌ์šฉ์ž๊ฐ€ Device์˜ ๋ฐฉํ–ฅ์„ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜, ํ™”๋ฉด์— ํ‚ค๋ณด๋“œ๊ฐ€ ํ‘œ์‹œ๋˜๊ฑฐ๋‚˜ ์ˆจ๊ฒจ์งˆ ๋•Œ์™€ ๊ฐ™์€ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ๋งˆ๋‹ค Observing๋œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. **Delegate Pattern**: ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๋Œ€์‹ ํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๊ฐ์ฒด์™€ ์ƒํ˜ธ์ž‘์šฉ์‘ ํ†ตํ•ด ํ–‰๋™ํ•  ๊ฐ์ฒด๋ฅผ ์ •์˜ํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, AppDelegate์—์„œ ์ƒˆ๋กœ์šด Remote notification์ด ๋„์ฐฉํ–ˆ์„ ๋•Œ ๋ฌด์—‡์ด ์‹คํ–‰๋˜์•ผ๋Š”์ง€ ํ•˜๋Š”์ง€ ์ •์˜ํ•˜์ง€๋งŒ, ์ด ์ฝ”๋“œ๊ฐ€ ์–ธ์ œ ์‹คํ–‰๋ ์ง€, ๋ช‡ ๋ฒˆ ์‹คํ–‰๋ ์ง€๋Š” ์•Œ ์ˆ˜ ์—†๋‹ค. **GCD(Grand Central Dispatch), Operations**: Task์˜ ์‹คํ–‰์„ ์ถ”์ƒํ™”ํ•˜๋Š” ๋ฐ ๋„์›€์„ ์ค€๋‹ค. ์ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•ด ์ฝ”๋“œ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰ํ•˜๋„๋ก ์˜ˆ์•ฝํ•˜๊ฑฐ๋‚˜, ๋‹ค์–‘ํ•œ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง„ ๋‹ค์–‘ํ•œ Queue์—์„œ ๋™์‹œ์— ์—ฌ๋Ÿฌ ์ž‘์—…์„ ์‹คํ–‰ํ•  ์ˆ˜ ์Šค๋‹ค. **Closure**: ์ฝ”๋“œ์—์„œ ๋‹ค๋ฅธ ๊ฐ์ฒด์˜ ์‹คํ–‰ ์—ฌ๋ถ€, ํšŸ์ˆ˜ ๋ฐ ์‹คํ–‰ํ•  Context๋ฅผ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ฝ”๋“œ๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค. > ๋Œ€๋ถ€๋ถ„์˜ ์ „ํ˜•์ ์ธ ์ฝ”๋“œ๋Š” ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€๋งŒ ์‹คํ–‰๋  ์ˆœ์„œ์— ๋Œ€ํ•ด ๊ฐ€์ •ํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. ๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์ข‹์€ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋žจ์„ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ๊ฐ€๋Šฅํ•˜๋‹ค. ๊ทธ์ € ๋ณต์žกํ•  ๋ฟ์ด๋‹ค. ![แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-04-13 22.01.44](https://hackmd.io/_uploads/rJ_rf-OeA.png) Apple์€ Timer, NotificationCenter, Core Data์™€ ๊ฐ™์€ ํ”„๋ ˆ์ž„์›Œํฌ์— Combine์„ ํ†ตํ•ฉํ•˜๊ณ  ์žˆ๋‹ค. ### Publisher > Publisher๋Š” Subscriber๊ฐ€ ํ•˜๋‚˜์ด์ƒ ์žˆ์„ ๋•Œ, ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๊ฐ’์„ Subscriber์—๊ฒŒ ๋‚ด๋ณด๋‚ผ ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ํƒ€์ž…์ด๋‹ค. ์ˆ˜ํ•™ ๊ณ„์‚ฐ, ๋„คํŠธ์›Œํ‚น, ์‚ฌ์šฉ์ž ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋“ฑ ๊ฑฐ์˜ ๋ชจ๋“  ๊ฒƒ์ด Publisher๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค. Publisher์˜ Input, Failure ๊ด€๋ จ ํƒ€์ž…์€ Publisher๊ฐ€ ์„ ์–ธํ•œ Output, Failure ํƒ€์ž…๊ณผ ์ผ์น˜ํ•ด์•ผ ํ•œ๋‹ค. Pulblisher๋Š” Subscriber๋ฅผ ์ˆ˜๋ฝํ•˜๊ธฐ ์œ„ํ•ด receive(subscriber:)๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ Publisher๋Š” Subscriber์—์„œ ์•„๋ž˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค. - recive(subscription:): ๊ตฌ๋… ์š”์ฒญ์„ ํ™•์ธํ•˜๊ณ  Subsciription ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. Subscriber๋Š” subscription์„ ์‚ฌ์šฉํ•˜์—ฌ Publisher์—๊ฒŒ Element๋ฅผ ์š”๊ตฌํ•˜๊ณ  ์ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Pulisheing์„ ์ทจ์†Œํ•  ์ˆ˜ ์žˆ๋‹ค. - receive(_:): Publisher์—์„œ Subscriber์—๊ฒŒ Element ํ•˜๋‚˜๋ฅผ ์ „๋‹ฌํ•œ๋‹ค. - receive(completion:): Publishing์ด ์ •์ƒ, ์˜ค๋ฅ˜์™€ ํ•จ๊ฒŒ ์ข…๋ฃŒ๋˜์—ˆ์Œ์„ Subscriber์—๊ฒŒ ์•Œ๋ฆฐ๋‹ค. ๋ชจ๋“  Publisher๋Š” Downstream subscriber๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋ ค๋ฉด ์ด ๊ณ„์•ฝ์„ ์ค€์ˆ˜ํ•ด์•ผํ•œ๋‹ค. Publisher์˜ ํ™•์žฅ ๊ธฐ๋Šฅ์€ ์ •๊ตํ•œ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ์ฒด์ธ์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ๊ตฌ์„ฑํ•˜๋Š” ๋‹ค์–‘ํ•œ ์—ฐ์‚ฐ์ž๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ Operator๋Š” Publisher๋Š” ํ”„๋กœํ† ์ฝœ์„ ๊ตฌํ˜„ํ•˜๋Š” ํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํƒ€์ž…์˜ ๋Œ€๋ถ€๋ถ„์€ Publisher ์—ด๊ฑฐํ˜•์˜ ํ™•์žฅ์œผ๋กœ ์กด์žฌํ•จ. ์˜ˆ๋ฅผ ๋“ค์–ด, map(_:) Operator๋Š” Publishers.Map์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜. Combine์˜ AsyncSequence์™€ ์œ ์‚ฌํ•˜์ง€๋งŒ ๊ตฌ๋ณ„๋˜๋Š” ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. Publisher์™€ AsyncSequence๋Š” ๋ชจ๋‘ ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ Element๋ฅผ ๋งŒ๋“ค์ง€๋งŒ ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค. **Combine** - pull ๋ชจ๋ธ์€ Subsciber๊ฐ€ Publisher๋กœ๋ถ€ํ„ฐ Element๋ฅผ ์š”์ฒญ ```swift import Combine let subject = PassthroughSubject<Int, Never>() // ๊ตฌ๋…์ž ์ƒ์„ฑ ๋ฐ ๋ฐ์ดํ„ฐ ์š”์ฒญ let subscriber = Subscribers.Sink<Int, Never>( receiveCompletion: { completion in switch completion { case .finished: print("Received completion") case .failure(let error): print("Received error: \(error)") } }, receiveValue: { value in print("Received value: \(value)") } ) subject.subscribe(subscriber) // ๊ฐ’ ๋ณด๋‚ด๊ธฐ subject.send(1) subject.send(2) subject.send(3) // ๋ฐœํ–‰์ž ์™„๋ฃŒ subject.send(completion: .finished) ``` > ์ด ์ฝ”๋“œ์—์„œ subject๋Š” ์š”์†Œ๋ฅผ ๋ฐฉ์ถœํ•  ์ˆ˜ ์žˆ๊ณ , Sink ๊ตฌ๋…์ž๋Š” ์ด๋Ÿฌํ•œ ์š”์†Œ๋ฅผ ๋ฐ›์•„ ์ฒ˜๋ฆฌ. subscribe ํ˜ธ์ถœ๋กœ ๊ตฌ๋…์„ ์‹œ์ž‘ํ•˜๊ณ , send ๋ฉ”์†Œ๋“œ๋กœ ์š”์†Œ๋ฅผ ๋ฐฉ์ถœํ•จ. **Async** - for-await-in ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•ด AsyncSequence์—์„œ ๋งŒ๋“  Element๋ฅผ ๋ฐ˜๋ณต ```swift let stream = AsyncStream<Int> { continuation in // ์š”์†Œ๋ฅผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ฐฉ์ถœ continuation.yield(1) continuation.yield(2) continuation.yield(3) // ์ŠคํŠธ๋ฆผ ์ข…๋ฃŒ continuation.finish() } Task { // ๋น„๋™๊ธฐ์ ์œผ๋กœ ์š”์†Œ ๋ฐ˜๋ณต for await number in stream { print("Received number: \(number)") } print("Stream completed") } ``` **important** > ๋‘ API ๋ชจ๋‘ Element๋ฅผ Mapping, Filteringํ•ด์„œ Sequence๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•˜์ง€๋งŒ Combine๋งŒ์ด **`debounce(for:scheduler:options:)`**,**`throttle(for:scheduler:latest:) `** ์™€ ๊ฐ™์€ ์‹œ๊ฐ„ ๊ธฐ๋ฐ˜ ์ž‘์—…๊ณผ **`merge(with:)`** , **`combineLatest(::`** ๊ฐ™์€ ๊ฒฐํ•ฉ ์ž‘์—…์„ ์ œ๊ณตํ•œ๋‹ค. **Combine๊ณผ Swift์˜ ๋™์‹œ์„ฑ ๋ชจ๋ธ ์‚ฌ์ด์˜ ์—ฐ๊ฒฐ ๋ฐฉ๋ฒ•** - ์ด ๋‘ ๊ธฐ์ˆ ์„ ํ†ตํ•ฉํ•˜๊ธฐ ์œ„ํ•ด, ๋ฐœํ–‰์ž๊ฐ€ ๋‚ด๋ณด๋‚ด๋Š” ์š”์†Œ๋“ค์„ AsyncSequence๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Subscriber๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๋Œ€์‹ , Swift์˜ for-await-in ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ์š”์†Œ๋“ค์„ ๋ฐ˜๋ณต์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. ```swift import Combine import Foundation // Combine Publisher๋ฅผ AsyncSequence๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ํ™•์žฅ extension Publisher { func asAsyncSequence() -> AsyncThrowingStream<Output, Error> { AsyncThrowingStream { continuation in let cancellable = self.sink( receiveCompletion: { completion in switch completion { case .finished: continuation.finish() case .failure(let error): continuation.finish(throwing: error) } }, receiveValue: { value in continuation.yield(value) } ) continuation.onTermination = { @Sendable _ in cancellable.cancel() } } } } ``` > Publisher๋ฅผ AsyncSequence๋กœ ๋ณ€ํ™˜ํ•˜๊ณ , for-await-in ๊ตฌ๋ฌธ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜๋ณต ์ฒ˜๋ฆฌ ```swift import Combine // Combine์„ ์‚ฌ์šฉํ•œ ๊ฐ„๋‹จํ•œ Publisher ์ƒ์„ฑ let numbersPublisher = PassthroughSubject<Int, Never>() numbersPublisher.send(1) numbersPublisher.send(2) numbersPublisher.send(3) numbersPublisher.send(completion: .finished) // ๋น„๋™๊ธฐ ์ž‘์—… Task { for try await number in numbersPublisher.asAsyncSequence() { print("Received number: \(number)") } print("All numbers received and sequence has finished.") } // ๊ฐ’์„ ๋ณด๋‚ด๊ธฐ ์œ„ํ•œ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ Task { numbersPublisher.send(4) numbersPublisher.send(5) numbersPublisher.send(6) numbersPublisher.send(completion: .finished) } ``` > PassthroughSubject๋กœ Publisher๋ฅผ ์ƒ์„ฑํ•˜๊ณ , AsyncSequence๋กœ ๋ณ€ํ™˜ํ•œ ๋’ค, for-await-in ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ’์„ ์ฒ˜๋ฆฌ #### Creating Your Own Publishers Publisher ํ”„๋กœํ† ์ฝœ์„ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋Š” ๋Œ€์‹ , Combine ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์ œ๊ณตํ•˜๋Š” ์—ฌ๋Ÿฌ ํƒ€์ž… ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•ด Own Publisher๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. - PassthroughSubject์™€ ๊ฐ™์€ Subject์˜ ๊ตฌ์ฒด์ ์ธ ํ•˜์œ„ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•„์š”ํ•  ๋•Œ send(_:) ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๊ฐ’์„ ๋ฐœํ–‰ - CurrentValueSubject๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ์ฃผ์ œ์˜ ๊ธฐ๋ณธ ๊ฐ’์ด ์—…๋ฐ์ดํŠธ๋  ๋•Œ๋งˆ๋‹ค ๊ฐ’์„ ๋ฐœํ–‰ - ํ”„๋กœํผํ‹ฐ์— @Published ์ฃผ์„์„ ์ถ”๊ฐ€ํ•ด์„œ ์‚ฌ์šฉํ•˜๋ฉด, ํ”„๋กœํผํ‹ฐ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์ด๋ฒคํŠธ๋ฅผ ๋ฐฉ์ถœํ•˜๋Š” Publisher๊ฐ€ ํ”„๋กœํผํ‹ฐ์— ์ถ”๊ฐ€๋œ๋‹ค. **NOTE** > Upstream: ๋ฐ์ดํ„ฐ ์†Œ์Šค ๋˜๋А ์ด์ „ Operator๋ฅผ ์ง€์นญํ•œ๋‹ค. ์–ด๋–ค Publisher์— ๋Œ€ํ•ด ์ƒ๊ฐํ•ด๋ณผ ๋•Œ, Upstream์€ Publisher๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋Š” ์ด์ „ ๋‹จ๊ณ„๋‚˜ Element์ด๋‹ค. ์ฆ‰, ํŠน์ • Operator ๋˜๋Š” Publisher์˜ ๊ด€์ ์—์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ์˜ค๋Š” ๋ฐฉํ–ฅ์„ ๋งํ•œ๋‹ค. - ์—ฌ๋Ÿฌ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์น˜๋Š” ๊ฒฝ์šฐ, ๊ฐ ๋‹จ๊ณ„์˜ ์ž…๋ ฅ ๋ถ€๋ถ„์€ Upstream์ด๋‹ค. > Downstream: ๋ฐ์ดํ„ฐ ์ˆ˜์‹ ์ž ๋˜๋Š” ์ดํ›„ Operator๋ฅผ ์˜๋ฏธํ•œ๋‹ค. Downstream์€ Publisher์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„ ์ถ”๊ฐ€ ์ฒ˜๋ฆฌํ•˜๋Š” ๋‹ค์Œ ๋‹จ๊ณ„๋‚˜ Element์ด๋‹ค. - Operator Chain์—์„œ ๊ฐ Operator๋Š” ์ž์‹ ์˜ ์ž…๋ ฅ์„ ๋ฐ›๋Š” upstream๊ณผ ์ถœ๋ ฅ์„ ๋ณด๋‚ด๋Š” downstream ์‚ฌ์ด์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค. ```swift import Combine let subject = PassthroughSubject<Int, Never>() let subscription = subject .map { $0 * 2 } // ์ฒซ ๋ฒˆ์งธ ์—ฐ์‚ฐ์ž (upstream: subject, downstream: filter) .filter { $0 > 5 } // ๋‘ ๋ฒˆ์งธ ์—ฐ์‚ฐ์ž (upstream: map, downstream: sink) .sink(receiveValue: { print("Received \($0)") }) // ๊ฐ’ ๋ฐฉ์ถœ subject.send(1) subject.send(3) subject.send(4) ``` ### Subscriber > Publisher๋กœ๋ถ€ํ„ฐ ์ž…๋ ฅ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ํƒ€์ž…์„ ์„ ์–ธํ•˜๋Š” ํ”„๋กœํ† ์ฝœ์ด๋‹ค. - Publisher๋กœ๋ถ€ํ„ฐ Element์˜ ์ŠคํŠธ๋ฆผ์„ ๋ฐ›๋Š” Subscriber๋Š” ๊ด€๊ณ„์˜ ๋ณ€ํ™”๋ฅผ ์„ค๋ช…ํ•˜๋Š” ์ƒ๋ช…์ฃผ๊ธฐ ์ด๋ฒคํŠธ์™€ ํ•จ๊ป˜ ๋ฐ›๋Š”๋‹ค. Subscriber์˜ Input, Failure๋Š” Publisher์˜ Output, Failure ํƒ€์ž…๊ณผ ์ผ์น˜ํ•ด์•ผํ•œ๋‹ค. Subscriber๋ฅผ Publisher์— ์—ฐ๊ฒฐํ•˜๋ ค๋ฉด Publisher์˜ subscribe(:)๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. ํ˜ธ์ถœ ํ›„, Publisher๋Š” Subscirber์˜ receive(subscription:)๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. ์ด ๊ณผ์ •์€ Subscriber์—๊ฒŒ subscription ์ธ์Šคํ„ด์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š”๋ฐ ์ด ์ธ์Šคํ„ด์Šค๋ฅผ ์ด์šฉํ•ด Publisher์—๊ฒŒ Element๋ฅผ ์š”์ฒญํ•˜๊ฑฐ๋‚˜ ํ•„์š”ํ•  ๊ฒฝ์šฐ ๊ตฌ๋…์„ ์ทจ์†Œํ•  ์ˆ˜ ์žˆ๋‹ค. ์ดˆ๊ธฐ ์š”์ฒญ์„ ๋ฐ›์€ ํ›„, Publisher๋Š” receive(_:)๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด ๊ฐ€๋Šฅํ•œ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ƒˆ๋กœ์šด Elements๋ฅผ ์ „๋‹ฌํ•œ๋‹ค. ๋ฐœํ–‰์ด ์ข…๋ฃŒ๋  ๋•Œ๋Š”, ์™„๋ฃŒ ๋ฐ ์˜ค๋ฅ˜๋กœ ์ธํ•œ ์ข…๋ฃŒ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” Subscribers.Completion ํƒ€์ž…์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด receive(completion:)๋ฅผ ํ˜ธ์ถœ. **Subscriber Operator** - sink(receiveCompletion:receiveValue:): ์™„๋ฃŒ ์‹ ํ˜ธ๋ฅผ ๋ฐ›์„ ๋•Œ๋งˆ๋‹ค, ์ƒˆ ์š”์†Œ๋ฅผ ๋ฐ›์„ ๋•Œ๋งˆ๋‹ค ์ž„์˜์˜ ํด๋กœ์ €๋ฅผ ์‹คํ–‰ ```swift let subscription = publisher .sink( receiveCompletion: { completion in switch completion { case .finished: print("Completed successfully.") case .failure(let error): print("Completed with an error: \(error)") } }, receiveValue: { value in print("Received value: \(value)") } ) ``` - assign(to: on:): ์ฃผ์–ด์ง„ ์ธ์Šคํ„ด์Šค์˜ ํ‚ค ๊ฒฝ๋กœ๋กœ ์‹๋ณ„๋œ ์†์„ฑ์— ๊ฐ ์ƒˆ๋กœ ๋ฐ›์€ ๊ฐ’์„ ๊ธฐ๋ก, Subsriber๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ์ฝ”๋“œ ์—†์ด ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•ด ๋ฐ์ดํ„ฐ ๋ชจ๋ธ์˜ ํ”„๋กœํผํ‹ฐ๋‚˜ UI ์ปจํŠธ๋กค์— ๋ฐ”์ธ๋”ฉํ•˜์—ฌ ํ‚ค ๊ฒฝ๋กœ๋ฅผ ํ†ตํ•ด ํ™”๋ฉด์— ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค. ```swift let subscription = publisher .assign(to: \.someProperty, on: someObject) ``` ### Subscription ๊ตฌ๋…์ด ๋๋‚  ๋•Œ, Subscriber๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด Chain ์‹œ์ž‘ ๋ถ€๋ถ„์—์„œ Publisher๊ฐ€ ํ™œ์„ฑํ™” ๋œ๋‹ค. Publisher๋Š” ์ž ์žฌ์ ์œผ๋กœ ์ถœ๋ ฅ์„ ๋ฐ›์„ Subscriber๊ฐ€ ์—†์œผ๋ฉด ์–ด๋–ค ๊ฐ’๋„ ๋‚ด๋ณด๋‚ด์ง€ ์•Š๋Š”๋‹ค. ๊ตฌ๋…์€ ์‚ฌ์šฉ์ž ์ง€์ • ์ฝ”๋“œ์™€ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด ๋น„๋™๊ธฐ ์ด๋ฒคํŠธ ์ฒด์ธ์„ ํ•œ ๋ฒˆ๋งŒ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค. full-Combine์œผ๋กœ ์ „ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ ๊ตฌ๋…์„ ํ†ตํ•ด ์•ฑ์˜ logic์„ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์™„๋ฃŒ๋˜๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ push, pullํ•˜๊ฑฐ๋‚˜ ๊ฐ์ฒด๋ฅผ ์ฝœ๋ฐฑํ•  ํ•„์š”์—†์ด Combine ์‹œ์Šคํ…œ์ด ๋ชจ๋“  ๊ฒƒ์„ ์‹คํ–‰ํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค. **Cancellable** - Protocol Cancellable๋ผ๋Š” ํ”„๋กœํ† ์ฝœ๋กœ ๊ตฌ๋…์˜ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ด€๋ฆฌํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. ์‹œ์Šคํ…œ์—์„œ ์ œ๊ณตํ•˜๋Š” sink, asign ๋ชจ๋‘ Cancellable์„ ๋”ฐ๋ฅธ๋‹ค. > cancel()์„ ํ˜ธ์ถœํ•˜๋ฉด ํ• ๋‹น๋œ ๋ฆฌ์†Œ์Šค๊ฐ€ ํ•ด์ œ๋œ๋‹ค. ๋˜ํ•œ ํƒ€์ด๋จธ, ๋„คํŠธ์›Œํฌ ์•ก์„ธ์Šค ๋˜๋Š” ๋””์Šคํฌ I/O์™€ ๊ฐ™์€ side-effects๋„ ์ค‘์ง€ํ•œ๋‹ค. **AnyCancellable** - Class ์ทจ์†Œ๋  ๋•Œ ์ œ๊ณต๋œ ํด๋กœ์ €๋ฅผ ์‹คํ–‰ํ•˜๋Š” ํƒ€์ž…์„ ์ง€์šฐ๋Š” ์ทจ์†Œ ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค > AnyCancellable ์ธ์Šคํ„ด์Šค๋Š” ์ดˆ๊ธฐํ™”๊ฐ€ ํ•ด์ œ๋˜๋ฉด ์ž๋™์œผ๋กœ cancel()์„ ํ˜ธ์ถœ