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

[Combine] Combine, Publisher, Subscriber ์— ๋Œ€ํ•ด์„œ

by Jouureee 2022. 4. 17.

์˜ค๋Š˜์€ Apple ์—์„œ ๋งŒ๋“  Reactive ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์œ„ํ•œ ํ”„๋ ˆ์ž„ ์›Œํฌ "Combine"์— ๋Œ€ํ•ด ์ •๋ฆฌ ํ•ด๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณค WWDC2021์—์„œ ์ƒˆ๋กœ ๋‚˜์˜จ Concurrency์— ๋Œ€ํ•ด์„œ๋„ ์•Œ์•„๋ณผ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

 

โžก๏ธ ์˜ค๋Š˜์˜ ๋ชฉํ‘œ : Combine, Publisher, Subscriber, Publisher ↔๏ธ Subscriber

 

์ •์˜ :

์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ์—ฐ์‚ฐ์ž๋“ค์„ ํ†ตํ•ด ๋น„๋™๊ธฐ ์ด๋ฒคํŠธ๋“ค์„ ํ•ธ๋“ค๋ง ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ

Combine ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ์‹œ๊ฐ„์ด ํ๋ฆ„์— ๋”ฐ๋ฅธ ๊ฐ’ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์„ ์–ธ์  Swift API๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฐ’์€ ๋‹ค์–‘ํ•œ ์ข…๋ฅ˜์˜ ๋น„๋™๊ธฐ ์ด๋ฒคํŠธ๋ฅผ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Combine์€ ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋Š” ๊ฐ’์„ ๋…ธ์ถœํ•˜๋Š” Publisher์™€ Publisher๋กœ๋ถ€ํ„ฐ ํ•ด๋‹น ๊ฐ’์„ ์ˆ˜์‹ ํ•˜๋Š” Subscriber๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.

 

Combine์€ ์‹œ๊ฐ„์— ๋”ฐ๋ฅธ ๊ฐ’ ํ๋ฆ„์„ Publisher์™€ Subscriber๋ฅผ ํ†ตํ•ด ๋‚˜ํƒ€๋‚ธ๋‹ค๊ณ  ํ•˜๋Š”๋ฐ ์ด ๋‘๊ฐ€์ง€์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์‚ดํŽด๋ด…์‹œ๋‹ค 

 

Publisher :

์‹œ๊ฐ„์— ๋”ฐ๋ฅธ ๊ฐ’์˜ ํ๋ฆ„์„ ์ „๋‹ฌํ• ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ํ”„๋กœํ† ์ฝœ

Output๊ณผ Failure ํƒ€์ž…์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ํƒ€์ž…์ด ์‹œ๊ฐ„์ด ํ๋ฆ„์— ๋”ฐ๋ผ ์ผ๋ จ์˜ ๊ฐ’์„ ์ „์†ก(transmit) ํ•  ์ˆ˜ ์žˆ์Œ์„ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.

Publisher๋Š” ํ•˜๋‚˜ ์ด์ƒ์˜ Subscriber ์ธ์Šคํ„ด์Šค์—๊ฒŒ element๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

Publisher๋Š” receive(subscriber:) ๋ฉ”์†Œ๋“œ๋กœ subscriber๋ฅผ  accept ํ•ฉ๋‹ˆ๋‹ค. 

 

Subscriber :

publisher๋กœ๋ถ€ํ„ฐ element์˜ stream์„ ๋ฐ›๋Š” ๊ฐ์ฒด

publihser๋ฅผ subscriber์— ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•

subscriber๋Š” ๊ฐ’์„ ์ˆ˜์‹  ๋ฐ›์„ ๋•Œ ๋™์ž‘๋ฉ๋‹ˆ๋‹ค.

publisher๋Š” subscriber๊ฐ€ ๊ฐ’์„ ์š”์ฒญํ•œ ๊ฒฝ์šฐ์—๋งŒ ๊ฐ’์„ ๋‚ด๋ณด๋ƒ…๋‹ˆ๋‹ค.

 

์ฆ‰ publisher๋Š” ์ด๋ฒคํŠธ๋“ค์„ ๋งŒ๋“ค์–ด๋‚ด๋Š”(publish) ์ฃผ์ฒด๊ณ  ๋งŒ๋“ค์–ด๋‚ธ ์ด๋ฒคํŠธ๋ฅผ ์“ฐ๊ธฐ ์œ„ํ•ด subscriber๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. 

RxSwift์—์„œ closure์˜ ๋ฐฉ์‹์˜ return ๊ฐ’์œผ๋กœ ๊ฐ’์„ ๋ฐœํ–‰ํ•˜๋Š” ๊ฒƒ์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๊ฐ’์„ ๋ฐœํ–‰ํ•ด ๊ฐ€์ง€๊ณ  ์žˆ๋Š” Observable๊ณผ Publisher์˜ ๊ฐœ๋…์ด ์œ ์‚ฌํ•œ๊ฑฐ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋Œ€๋กœ ๊ฐ’์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด subscribeํ•˜๋Š”๋ฐ ์ด๋•Œ ๊ฐ’์„ ์ €์žฅํ•˜๋Š” ์ฃผ์ฒด๊ฐ€ Subscriber๋ผ ์ƒ๊ฐํ•˜๋ฉด ๋ ๊ฑฐ ๊ฐ™์Šต๋‹ˆ๋‹ค. 

 

๊ทธ๋ ‡๋‹ค๋ฉด publisher์™€ subscriber๋ฅผ ์—ฐ๊ฒฐํ•  ๋ฐฉ๋ฒ•์ด ์žˆ์–ด์•ผ๊ฒ ์ฃ  ?

๋‹ค์Œ๊ณผ ๊ฐ™์ด 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  1. subscribe
  2. sink
  3. assign - (sink์™€๋Š” ๋‹ค๋ฅด๊ฒŒ publisher์˜ Failure ํƒ€์ž…์ด Never์ผ๋•Œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ)
//publisher ์ƒ์„ฑ
let publisherJust = Just("uri")

//subscribe ๋ฐฉ์‹
publisherJust.subscribe(UriSubscriber())

//sink ๋ฐฉ์‹
let subscriber = publisherJust.sink(receiveCompletion: { (result) in switch result {
case .finished:
    print("finished")
case .failure(let error):
    print(error.localizedDescription)
    }
}, receiveValue: { (value) in
    print(value)
    
})

์œ„ ์ฝ”๋“œ์— Just()๋Š” Publisher์˜ ํ•œ ์ข…๋ฅ˜์ž…๋‹ˆ๋‹ค. Just ์™ธ์—๋„ 

๋‹ค์–‘ํ•œ publisher๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค. 

๋‹ค์–‘ํ•œ publisher๋“ค -> https://developer.apple.com/documentation/combine

 

1. Subscribe ๋ฉ”์†Œ๋“œ ์‚ฌ์šฉํ•˜๊ธฐ

 publisherJust.subscribe(UriSubscriber())

publisher๊ฐ€ UriSubscriber()๋ฅผ ๊ตฌ๋…ํ•˜๊ณ  ์žˆ๋Š”๋ฐ์š”

์šฐ์„  Publisher์™€ Subscriber๊ฐ€ ์„œ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ๋•Œ๋Š” ํ•ญ์ƒ ๋‘ ๊ฐ€์ง€์˜ ํƒ€์ž…์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ๋จผ์ € Publisher ์ž…์žฅ์—์„œ๋Š” Output ํƒ€์ž…๊ณผ Failure ํƒ€์ž…์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๊ฒฝ์šฐ Failure ํƒ€์ž… ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด Output ํƒ€์ž…์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๋Š” Subscriber๋Š” Publisher์˜ outputํƒ€์ž…๊ณผ ๋™์ผํ•œ Input ํƒ€์ž…๊ณผ, ๊ทธ๋ฆฌ๊ณ  ๋™์ผํ•œ Failure ํƒ€์ž…์„ ๊ฐ€์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  recieveํ•จ์ˆ˜๊ฐ€ 3๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฒ˜์Œ publisher๊ฐ€  publisherJust.subscribe(UriSubscriber())๋ฅผ ํ˜ธ์ถœํ–ˆ์„๋•Œ ๊ตฌ๋…์„ ์„ฑ๊ณตํ–ˆ์Œ์„ ์•Œ๋ฆฌ๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

func receive(subscription: Subscription) {}

์ด๋•Œ subscriber์—๊ฒŒ subscription ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๋Š”๋ฐ publisher๊ฐ€ ๊ฐ€์ง„ ๊ฐ’์„ ์š”์ฒญํ•˜๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.

subscription.request(.unlimited)

.unlimited๋กœ ๋ฌดํ•œํ•œ ๊ฐ’์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค. 

 

๋‹ค๋ฅธ ์š”์ฒญ ๊ฐ’์œผ๋กœ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

- unlimited(๋ฌด์ œํ•œ)

- max(์ตœ๋Œ€ ๊ฐœ์ˆ˜ ์ œํ•œ)

- none(no elements. max(0)๊ณผ ๊ฐ™์Œ)

 

๋‘๋ฒˆ์งธ recieve()์ž…๋‹ˆ๋‹ค.

๊ตฌ๋… ์ดํ›„ publisher๊ฐ€ ์ƒˆ๋กญ๊ฒŒ ๋ฐœํ–‰ํ•œ element๊ฐ€ ์žˆ๋‹ค๋ฉด ๋ฐ›์•„๋“ค์ž…๋‹ˆ๋‹ค.

์–ผ๋งˆ๋‚˜ ๋งŽ์€ ๊ฐ’์„ ๋ฐœํ–‰ ๋ฐ›์„์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š”๋ฐ์š”.

 

๋‹ค๋ฅธ ์š”์ฒญ ๊ฐ’์œผ๋กœ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

- unlimited(publisher๊ฐ€ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋งŒํผ ๋ฌด์ œํ•œ ์š”์ฒญ)

- max(์ตœ๋Œ€ ๊ฐœ์ˆ˜ ์ œํ•œ)

- none(no elements. max(0)๊ณผ ๊ฐ™์Œ, ๋”์ด์ƒ ์š”์ฒญํ•˜์ง€ x)

 

 

๋งˆ์ง€๋ง‰ recieve() ์ž…๋‹ˆ๋‹ค.

func receive(completion: Subscribers.Completion<Never>) { //3. publisher์—๊ฒŒ publisher๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋˜๋Š” ์˜ค๋ฅ˜๋กœ publish๋ฅผ ์™„๋ฃŒํ–ˆ์Œ์„ ์•Œ๋ฆผ
        print("receive(completion: Subscribers.Completion<Never>)")
    }

publisher๊ฐ€ ๋”์ด์ƒ ๊ฐ’์„ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ error ๋ฐœ์ƒ์‹œ ์™„๋ฃŒ์˜ ์˜๋ฏธ๋กœ ์ด ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

subscriber๋ฅผ ์ง์ ‘ ๋งŒ๋“ค๊ณ  subscribe() ํ•˜๋Š” ๋ฐฉ์‹์€ ํ•„์š”์— ๋”ฐ๋ผ ๋ชจ๋“  ํ•จ์ˆ˜๊ฐ€ ๋ถˆ๋ฆด ํ•„์š”๊ฐ€ ์—†์„๊ฑฐ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

์ด๋ณด๋‹ค ๋”์šฑ ๊ฐ„๋‹จํ•œ ๋ฐฉ์‹์œผ๋กœ subscriber๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ์‹์ด ์žˆ์Šต๋‹ˆ๋‹ค. 

 

2. sink() ๋ฉ”์†Œ๋“œ 

๋˜ ๋‹ค๋ฅธ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

ํด๋กœ์ € ํ˜•์‹์œผ๋กœ subscriber๋ฅผ ๋งŒ๋“ค๊ณ  subscriber์—๊ฒŒ ๋ฆฌํ„ด๋˜๊ธฐ ์ „์— ๊ฐ’์„ ์ฆ‰์‹œ์ ์œผ๋กœ ์š”์ฒญํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

3. assign() ๋ฉ”์†Œ๋“œ

์ƒˆ๋กœ์šด ๊ฐ’์„ keyPath์— ๋”ฐ๋ผ ์ฃผ์–ด์ง„ ์ธ์Šคํ„ด์Šค์˜ property์— ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.

publisher์—์„œ ๋ฐœํ–‰ํ•œ ๊ฐ’์„ subscriber์—๊ฒŒ ๋ฆฌํ„ด๋˜๊ธฐ ์ „์— ๊ฐ’์„ ๋‹ค๋ฅธ property์— ํ• ๋‹นํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

์ด ํ๋ฆ„์„ ๋‹ค์‹œ ์‚ดํŽด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

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

[Combine] Cancellable์ด๋ž€  (0) 2023.04.17
[Combine] Scheduler๋ž€  (0) 2023.04.16
[Combine] ConnectablePublisher  (0) 2022.05.03
[Combine] Subject๋ž€ (AnyPublisher)  (0) 2022.04.17

๋Œ“๊ธ€