A subject can receive values from an upstream publisher, and also can pass along these values to its downstream subscribers.
: Subject๋ ์ ์คํธ๋ฆผ ๋ฐํ์๋ก๋ถํฐ ๊ฐ์ ์ ๋ฌ๋ฐ์ ์๋ ์๊ณ , ๋ค์ด์คํธ๋ฆผ ๊ตฌ๋ ์์๊ฒ ๊ฐ์ ์ ๋ฌํ ์๋ ์๋ค. ๋ ๊ฐ์ ๊ฐ์ง๊ณ ์์ ์๋ ์๋ค.
Subjects ์๋ 2๊ฐ์ง ์ข ๋ฅ๊ฐ ์๋๋ฐ, ์ฐ์ ๊ทธ ์ค ํ๋์ธ PassThroughSubject๋ก ๋ง๋ ์์๋ฅผ ํ๋ฒ ๋ณด์.
์๋๋ PassThroughSubject
๊ฐ ๊ตฌ๋
์ ์ญํ ์ ํ๋ ๋ชจ์ต์ด๋ค.
// ๋ฐํ์
let publisher = [1, 2, 3].publisher
// ๊ตฌ๋
์ ์ญํ ์ ํ passthroughsubject
let passThroughSubject = PassThroughSubject<Int, Never>()
// ๋์ ์ฎ์ผ๋ ค๋ฉด - AnySubscriber(s: Subject)๋ฅผ ํ์ฉํ ์ ์๋ค.
// (PassThroughSubject๋ Subject ํ๋กํ ์ฝ์ ์ค์ํ๋ค.)
let anySubscriber = AnySubscriber(passThroughSubject)
// PassThroguhSubject๋ฅผ ์ด์ฉํ์ฌ ๊ตฌ๋
๊ด๊ณ๊ฐ ์ฑ๋ฆฝ๋ ๋ชจ์ต (Subject์ ๊ตฌ๋
์ ์ญํ )
publisher.receive(subscriber: anySubscriber)
์ด๋ฒ์๋ ๋ฐํ์ ์ญํ ์ ํ๋ ๋ชจ์ต์ด๋ค.
// ๋ฐํ์ ์ญํ ์ ํ PassThroughSubject
let passThorughSubject = PassThroughSubject<Int, Never>()
// sink() ๋ฉ์๋๋ฅผ ํตํด ํด๋น passThroughSubject์ ์ฐ๊ฒฐ๋์ด์๋ ๋ค์ด์คํธ๋ฆผ ๊ตฌ๋
์๋ฅผ ์์ฑํ ์ ์๋ค.
// ๊ฐ์ ๊ตฌ๋
์์๊ฒ ๋ด๋ ค๋ค์ฃผ๊ธฐ ๋๋ฌธ์ ์ฌ๊ธฐ์๋ ๋ฐํ์ ์ญํ ์ ํ๋ค.
let newSubscriber = passthroughSubject
.sink { value in
print(value)
}
์ด๋ฐ์์ผ๋ก subject๋ ๋๊ฐ์ง ์ญํ ์ ๋ค ํ ์ ์๋ SOLID ์์น์ ์๋ฐฐ๋๋ ๊ณ ๋ง์ด ์น๊ตฌ.
์์์ Subject์๋ ๋๊ฐ์ง ์ข ๋ฅ๊ฐ ์๋ค๊ณ ํ๋๋ฐ, ์ด์ ๋ ์ด ๋๊ฐ์ง์ ๋ํด ์์๋ณด์.
์ฒซ๋ฒ์งธ๋ก ์ข์ ์ ์์์์ ๋ง๋ฌ๋ PassThroughSubject
, ๋๋ฒ์งธ๋ก CurrentValueSubject
๊ฐ ์๋ค.
๋๋ค ๊ณตํต์ ์ผ๋ก Subject ํ๋กํ ์ฝ์ ์ฑํํ์ฌ ์์ ๋ณด์๋ฏ์ด ๋ฐํ์ ๋ฐ ๊ตฌ๋ ์ ์ญํ ์ ์ํํด๋ผ ์ ์๋ค.
๋ฐํ์ ์ญํ ์ ๊ด์ ์์ ๋ subject์ ๋ค๋ฅธ ์ ์ด ์๋ค๋ฉด CurrentValueSubject
๋ ์ด๊ธฐ๊ฐ์ด ์๊ณ , PassThroughSubject
๋ ์ด๊ธฐ๊ฐ์ด ์๊ณ ๋ฐํ์ ์์ํ ์์ ๋ถํฐ ๊ฐ์ด ์๋ค๋ ์ ์ด๋ค.
CurrentValueSubject
๋ ์๋์ ๊ฐ์ด ์์ฑ์์ ์ด๊ธฐ๊ฐ์ ๋ด์์ผํ๋ค.
let currentSubject = CurrentValueSubject<Int, Never>(99)
PassThroughSubject
๋ ์์ฑ์์๋ ์ด๊ธฐ๊ฐ์ ๋ด์ ์ ์๋ค.
let passthroughSubject = PassthroughSubject<Int, Never>()
์ด๋ฌํ ๋์ ์ฐจ์ด๋๋ฌธ์, ๋ค์๊ณผ ๊ฐ์ ์ฐจ์ด๊ฐ ํ์๋๋ค.
"CurrentValueSubject ๋ ๊ตฌ๋ ์ด ์์๋๋ ์์ ์ ์ด๊ธฐ๊ฐ์ด ๊ฒ์๊ฐ ๋๊ธฐ ๋๋ฌธ์ ์ฐ๊ฒฐ์ด ๋์๋ง์ ๊ฐ์ด ๊ตฌ๋ ์์๊ฒ ์ ๋ฌ๋์ง๋ง, PassThroughSubject๋ ๊ตฌ๋ ์ด ์์๋๊ณ , ๊ทธ ํ์ ๊ฐ์ด ๊ฒ์๊ฐ ๋์์ ๋ ๊ตฌ๋ ์์๊ฒ ๊ฐ์ด ์ ๋ฌ๋๋ค."
์ด๊ฒ ๋ฌด์จ๋ง์ธ์ง๋ ์๋์ ์์๋ฅผ ๋ณด๋ฉด ํ๋ฒ์ ์ดํด๊ฐ ๊ฐ ๊ฒ์ด๋ค. ์ฐ์ ์ CurrentValueSubject
์ ๋์์ ์ดํด๋ณด์
// message ๋ฌธ์์ด ๋ณ์๊ฐ์ ๋ด์ currentValueSubject๋ฅผ ์์ฑํ๋ค. ์ฌ๊ธฐ์ message๋ ์ด๊ธฐ๊ฐ์ด๋ค.
let message = "๋ทํ๋ฆญ์ค ๊ตฌ๋
์ด ์์๋์์์ ์๋ฆฌ๋ ๋ฉ์์ง์
๋๋ค. ์๋น์ค๋ฅผ ๋ฐ๋ก ์ด์ฉํ์
๋ ๋ฉ๋๋ค."
let currentValueSubject = CurrentValueSubject<String, Never>(message)
// sink()๋ฉ์๋๋ฅผ ํตํด ๊ตฌ๋
์๋ฅผ ๋ฐ๋ก ์ฐ๊ฒฐํ๋ค.
// ๊ตฌ๋
์์ ์ฐ๊ฒฐ์ด ๋ ์งํ ๋ฐํ์๋ ๊ฐ์ ๊ฒ์ํ๋ฏ๋ก, currentValueSubject๋ ์ด๊ธฐ๊ฐ์ธ message ๊ฐ์ ๋ค์ด์คํธ๋ฆผ ๊ตฌ๋
์์๊ฒ ์ ๋ฌํ๋ค.
// ๋ค์ด์คํธ๋ฆผ ๊ตฌ๋
์๋ ํด๋น ๊ฐ์ ๋ฐ์์ print ํ๋ค.
let subscriber = currentValueSubject
.sink { message
print(message)
}
// ๋๋ฒ์งธ ๊ฐ์ ๊ฒ์ํ๋ค. - ๊ตฌ๋
์๋ ๋ค์ํ๋ฒ ์ ๋ฌ๋ฐ์ ๊ฐ์ print ํ๋ค
currentValueSubject.send("์๋ก์ด ์ํ ๋ฐ ๋๋ผ๋ง๊ฐ ์ถ์๋์์ต๋๋ค. ์ง๊ธ ๋ฐ๋ก ํ์ธํด๋ณด์ธ์!")
// - Output -
// "๋ทํ๋ฆญ์ค ๊ตฌ๋
์ด ์์๋์์์ ์๋ฆฌ๋ ๋ฉ์์ง์
๋๋ค. ์๋น์ค๋ฅผ ๋ฐ๋ก ์ด์ฉํ์
๋ ๋ฉ๋๋ค."
// "์๋ก์ด ์ํ ๋ฐ ๋๋ผ๋ง๊ฐ ์ถ์๋์์ต๋๋ค. ์ง๊ธ ๋ฐ๋ก ํ์ธํด๋ณด์ธ์!"
CurrentValueSubject
๋ ์ด๊ธฐ๊ฐ์ ๊ฐ์ง๊ณ , ๊ตฌ๋
์ด ์์๋๋ ์๊ฐ ๊ฐ์ ๋ค์ด์คํธ๋ฆผ ๊ตฌ๋
์์๊ฒ ์ ๋ฌํ๋ค.
์์ ๊ฐ์ ๋์์ PassThroughSubject
๋ก ๋์ผํ๊ฒ ํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ ๊น?
์์ ๋งํ๋ฏ์ด, PassThroughSubject
๋ CurrentValueSubject
์ ๋ค๋ฅด๊ฒ ์ด๊ธฐ๊ฐ์ด ์๋ค.
๊ทธ๋ฌ๋ฏ๋ก ๊ตฌ๋
์ด ์์๋ ์์ ์ด ์๋ PassThroughSubject
๊ฐ ๊ฐ์ ๊ฒ์ํ ์๊ฐ๋ถํฐ ๊ฐ์ด ์ ๋ฌ๋๋ค.
์ด๋ฒ์๋ ์ญ์ ์์ ๋ฅผ ๋ณด๋ฉด ์ดํด๊ฐ ๋จ๋ฒ์ ๋ ๊ฒ์ด๋ค.
let passThroughSubject = PassThroughSubject<String, Never>()
// sink()๋ฉ์๋๋ฅผ ํตํด ๊ตฌ๋
์๋ฅผ ๋ฐ๋ก ์ฐ๊ฒฐํ๋ค.
// ๊ตฌ๋
์์ ์ฐ๊ฒฐ์ด ๋ ์งํ ๋ฐํ์๋ ๊ฐ์ ๊ฒ์ํ์ง๋ง, PassThroughSubject๋ ์ด๊ธฐ๊ฐ์ด ์๊ธฐ๋๋ฌธ์ ๋ค์ด์คํธ๋ฆผ ๊ตฌ๋
์์๊ฒ ์ ๋ฌ๋๋ ๊ฐ์ด ์๋ค.
let subscriber = passThroughSubject
.sink { message
print(message)
}
let messageA = "๋ทํ๋ฆญ์ค ๊ตฌ๋
์ด ์์๋์์์ ์๋ฆฌ๋ ๋ฉ์์ง์
๋๋ค. ์๋น์ค๋ฅผ ๋ฐ๋ก ์ด์ฉํ์
๋ ๋ฉ๋๋ค."
let messageB = "์๋ก์ด ์ํ ๋ฐ ๋๋ผ๋ง๊ฐ ์ถ์๋์์ต๋๋ค. ์ง๊ธ ๋ฐ๋ก ํ์ธํด๋ณด์ธ์!"
// send()๋ฅผ ํตํด ๊ฐ์ ๊ฒ์ํ์ฌ ๊ฐ์ ๊ตฌ๋
์์๊ฒ ์ ๋ฌํ๋ค.
passThroughSubject.send(messageA)
passThroughSubject.send(messageB)
// - Output -
// "๋ทํ๋ฆญ์ค ๊ตฌ๋
์ด ์์๋์์์ ์๋ฆฌ๋ ๋ฉ์์ง์
๋๋ค. ์๋น์ค๋ฅผ ๋ฐ๋ก ์ด์ฉํ์
๋ ๋ฉ๋๋ค."
// "์๋ก์ด ์ํ ๋ฐ ๋๋ผ๋ง๊ฐ ์ถ์๋์์ต๋๋ค. ์ง๊ธ ๋ฐ๋ก ํ์ธํด๋ณด์ธ์!"
Subject๋ completion ์ด๋ฒคํธ๋ฅผ ๋ฐ์ผ๋ฉด ๋์ด์ ๊ฐ์ ๋ฐ์ง ์๋๋ค.
์ด๋ ๋ง์น ์๊ฐ ๊ตฌ๋ ์๋น์ค๋ฅผ ์ด์ฉํ๋ ๊ตฌ๋ ์์๊ฒ ์๋น์ค๊ฐ ๋๋ฌ์์ ์๋ฆฌ๊ณ , ๊ตฌ๋ ์๋น์ค๋ ์๋ก์ด ์๊ฐ ๊ตฌ๋ ์ํ์ ์ถ์ํ๋ค. ์๋น์ค๊ฐ ์ข ๋ฃ๋ ๊ตฌ๋ ์๋ ๋์ด์ ํด๋น ์๋น์ค์ ๊ตฌ๋ ์ํ์ ๋ฐ์๋ณผ ์ ์๊ณ , ๋ง์ง๋ง์ผ๋ก ๋ฐ์๋ณธ ์ํ์ ๊ฐ์ง๊ณ ์๋ ๊ฒ ์ ์ฌํ๋ค๊ณ ๋ณผ ์ ์๊ฒ ๋ค.
let currentValueSubject = CurrentValueSubject<Int, Never>(1)
print(currentValueSubject.value)
// 1
currentValueSubject.send(2)
print(currentValueSubject.value)
// 2
currentValueSubject.send(completion: .finished)
currentValueSubject.send(10)
print(currentValueSubject.value)
// 10์ด ์๋ 2๋ฅผ ์ถ๋ ฅํ๋ค
@Published ์๋ ๋ค๋ฅด๊ฒ Protocol ์ ์ธ์ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค. (Property wrapper๋ ํ๋กํ ์ฝ ์์์ ์ฌ์ฉ์ด ๋ถ๊ฐ๋ฅํ๋ค)
@Published ์๋ ๋ค๋ฅด๊ฒ error type ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
์ด ๋ถ๋ถ์ ๋ํด์๋ ์ถ๊ฐ์ ์ธ ์กฐ์ฌ๊ฐ ํ์ํ๋ค ๐งช