Combine์ด ๋ฌด์์ผ๊น? Apple์ด ์ค๋ช ํ๋ ๊ฒ์ ๋ค์ด๋ณด์.
What is Combine
์ด๋ฒคํธ ์ฒ๋ฆฌ ์ฐ์ฐ์๋ฅผ ๊ฒฐํํ์ฌ ๋น๋๊ธฐ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ
์ผ๋จ ๋น๋๊ธฐ ์ด๋ฒคํธ๊ฐ ๋ฌด์์ด ์๋์ง๋ถํฐ ์์๋ณด์. ์ด๋ฅผ ์ค๋ช ํ๊ธฐ ์ํด์ WWDC์์๋ Create Account ํ์ด์ง๋ฅผ ๋ง๋๋ ๊ฒ์ ์์๋ก ํ์ฌ ์ค๋ช ์ ์ด์ด๊ฐ๋ค.
์๊ตฌ์ฌํญ์ ์์ ๊ฐ๋ค. username ์ ํจ์ฑ ํ๋จ, password matching ํ๋จ, ๊ทธ๋ฆฌ๊ณ ์ด๊ฒ๋ค์ด ๋ง์ ๊ฒฝ์ฐ, ๋ฒํผ์ด ํ์ฑํ๋๋ ๊ฒ, ์ด ์ธ๊ฐ์ง ์ด๋ค.
์ด๊ฑธ ๊ฐ๋ฅ์ผํ๊ธฐ ์ํด์๋ ๋จผ์ , interaction ์ฌ๋ถ๋ฅผ ์ ๋ฌํด์ฃผ์ด์ผ ํ๋ค. ์ด ๋ถ๋ถ์์ Target/Action ๋์์ธ ํจํด์ด ์ฌ์ฉ๋๋ค. ์ ์ ๊ฐ TextField์ ์ ๋ ฅํ ์ดํ, ์ฆ, ๋ณ๊ฒฝ๋ ๋๋ง๋ค ์๋ฒ ํต์ ์ ํตํด ๊ฒ์ฆ์ ํ๋ค๋ฉด network resource ๋ญ๋น์ผ ๊ฒ์ด๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ํน์ ์๊ฐ ๊ฐ๊ฒฉ์ ๋๊ณ ๋คํธ์ํฌ ํต์ ์ ํด์ผ ํ๋ค. ์ด ๋ถ๋ถ์์๋ Timer๊ฐ ์ฌ์ฉ๋๋ค. ๋คํธ์ํฌ Progress update๋ฅผ ์ํด์๋ KVO๋ฅผ ํตํด ์ฒ๋ฆฌํ ์๊ฐ์ด๋ค.
์ฌ์ฉ์๊ฐ TextField์ ๊ฐ์ ์ ๋ ฅํ๋ฉด, URLSession์ ํตํด ๋คํธ์ํฌ ์์ฒญ์ ๋ณด๋ด๊ณ , ์ด 3๊ฐ์ TextField์ ์ ๋ ฅ๊ฐ์ด ๋ชจ๋ ๋ด๊ฒจ์ก๋ค๋ฉด, ์ด ๋ชจ๋ ๊ฐ์ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ํ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก Merge๊ฐ ํ์ํ๋ค. ๋ชจ๋ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ํต๊ณผํ๋ค๋ฉด, ํ๋จ์ Create Account Button์ Enable ์ฌ๋ถ๋ฅผ ๋ณ๊ฒฝํด์ฃผ์ด์ผ ํ๋ค.
๊ฒฐ๊ณผ์ ์ผ๋ก Cocoa API์์๋ ๋ค์๊ณผ ๊ฐ์ ๋น๋๊ธฐ API๋ค์ ๋ง๋๊ฒ ๋๋ค.
์ด๋ ๊ฒ ๋ค์ํ ์์๋ค์ด ์๋๋ฐ, ์ด ๋ ์๋ค์ ๊ฐ๊ฐ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ๋ ๋ค๋ฅด๋ค. ๊ทธ๋์ ์ด๊ฒ๋ค์ ์ฎ์ด์ ์ฐ๋ ค๋ ๋ฌธ์ ๊ฐ ์๊ธฐ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์๋ค. ์ด๋ฌํ ๋ฌธ์ ์ ์ ์ฐฉ์ํ์ฌ Apple์ ์ด ๋ ์๋ค์ ๊ณตํต์ ์ ์ถ์ถํ๊ฒ ๋๋๋ฐ ๊ทธ๊ฒ์ด Combine์ด๋ค.
Combine
A unified, declarative API for processing values over time.
์๊ฐ์ ํ๋ฆ์ ๋ฐ๋ผ ์ฒ๋ฆฌํ๋ โ์ ์ธ์ โ API์ด๋ค. ํน์ง์ ๋ค์๊ณผ ๊ฐ๋ค.
- Generic: Genericํ๊ฒ ์์ฑ ํ, ์ด๊ณณ ์ ๊ณณ์์ ํ์ฉ์ด ๊ฐ๋ฅํ๋ค.
- Type Safe: compile time์ Error๋ฅผ ์ก์ ์ ์๋ค.
- Composition first: functional programming์ ํจ์ ์กฐํฉ ๊ฐ๋ ์ ์ฐจ์ฉํ์ฌ ์ฌ๋ฌ operator๋ฅผ ์ฐ๊ฒฐํ์ฌ ์ํ๋ ๊ฒฐ๊ณผ๋ฅผ ์ป๋ ๊ฒ์ ์ง์คํ๋ค.
- Request driven: ์์ฒญ์์ ์ฒ๋ฆฌ๋๋ค. ํ์ํ ๋๋ง ์ฒ๋ฆฌ๋๋ Resource๋ฅผ ์๋ ์ ์๋ค.
Publishers
์ด๋ป๊ฒ Value์ Error๊ฐ ์์ฐ๋ ๊ฒ์ธ์ง์ ๋ํด ์ ์ํ๋ค. ๊ฐํ์
, ์ฆ struct
๋ก ์ ์ธ๋์ด ์์ผ๋ฉฐ, Subscriber๋ค์ ๋ฑ๋ก์ ๋ฐ๋ ๋
์์ด๋ค.
- Publish Values and Error
- Value Type: struct
protocol Publisher {
associatedtype Output
associatedtype Failure: Error
func subscribe<S: Subscriber>(_ subscriber: S)
where S.Input == Output, S.Failure == Failure
}
๋๊ฐ์ ์ฐ๊ด๊ฐ์ด ์๋๋ฐ, Output
, Failure
์ด๋ค. ์ฑ๊ณต์์ ๊ฐ์ ์ฃผ๋ ๋
์์ด Output
์ด๊ณ ์คํจํ ์ ์ฃผ๋ Error๊ฐ Failure
์ด๋ค. ๋ง์ฝ Error๋ฅผ ์ค ์ ์์ ๊ฒฝ์ฐ Never
๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
Publisher๋ ๋ฑ ํ๋์ ํจ์๋ฅผ ๊ฐ์ง๊ณ ์๋๋ฐ, subscrive()
์ด๋ค. ํด๋น ํจ์๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ์ ์ฝ์ด ํ์ํ๋ฐ, publisher์ ๊ตฌ๋
์ ๋ฐ๋ subscriber์ input๊ณผ Failure type์ด ๊ฐ์์ผ ํ๋ค. ์ด ๋ถ๋ถ์ ์ฌ์ค ๋น์ฐํ๋ค.
// Notification Center
extension NotificationCenter {
struct Publisher: Combine.Publisher {
typealias Output = Notification
typealias Failure = Never
init(center: NotificationCenter, name: Notification.Name, object: Any? = nil)
}
}
Notification Center์๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์์ ๊ฐ์ extension์ด ์ถ๊ฐ๋์ด ์๋ค. ์ค์ ๋ก struct type์ด๋ฉฐ, output type์ Notification
, Failure type์ Never
์ด๋ค.
Subscribers
Subscriber๋ Publisher์ ๋์ฒ์ ์ ์๋ ๋ ์์ด๋ค. Publisher๊ฐ ๋ง๋ค์ด๋ด๋ ๊ฐ์ ๋ฐ๊ณ , Publisher๊ฐ ๋ง์ฝ ์ ํํ๋ค๋ฉด, (์ฆ, ๊ฐ ๋ช๊ฐ๋ฅผ ๋ด๋ณด๋ด๊ณ ์ฌ์ฉ๊ฐ์น๊ฐ ์ฌ๋ผ์ง๋ ๋ ์๋ค์ ๋งํจ) ๋๋ฌ์ ๋ ํ๋ ํ๋์ ์ ์ํ ์ ์๋ ๋ ์์ด๋ค. Reference Type์ด๋ค. ์ฆ Class๋ผ๋ ๋ง์ด๋ค.
- Reference Type: Class
- Receive Values and Completion: ๊ฐ์ ๋ฐ๊ณ , ๋๋ฌ์ ๋ ๋์ ์ ์
protocol Subscriber {
associatedtype Input
associatedtype Failure: Error
func receive(subscription: Subscription)
func receive(_ input: Input) -> Subscribers.Demand
func receive(completion: Subscribers.Completion<Failure>)
}
์ฐ๊ด๊ฐ 2๊ฐ, Input
, Failure
๊ฐ ์๋ ๊ฒ์ ํ์ธํ ์ ์๋ค. ์๊น ๋งํ๋ฏ Publisher์ Type์ด ๊ฐ์์ผ ๋ฑ๋ก์ด ๊ฐ๋ฅํ๋ค. Error Type์ด ์๋ ๊ฒฝ์ฐ์๋ ๋ง์ฐฌ๊ฐ์ง๋ก Never
๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
์ถ๊ฐ์ ์ผ๋ก 3๊ฐ์ ํจ์๋ฅผ ๊ฐ์ง๊ณ ์๋ค. ๋จผ์ , Subscription์ ๋ฐ์ ์ ์๋๋ฐ, Subscription์ ์ด๋ป๊ฒ Subscriber๊ฐ Publihser๋ก ๋ฐ์๋ data๋ฅผ Subscriber๋ก ์ค ์ ์๋์ง์ ๋ํ ๊ฒ์ด๋ค. (?)
๋๋ฒ์งธ๋ก๋ Input์ ๋ฐ์ ์ ์์ผ๋ฉฐ, ๋ง์ง๋ง์ผ๋ก๋ finiteํ Publihser์ ์ฐ๊ฒฐ๋ ๊ฒฝ์ฐ completion์ ๋ฐ๋๋ฐ, Finished๊ฑฐ๋ Failure์ผ ๋์ ๋์์ ์ ํ ์ ์๋ค.
extension Subscribers {
class Assign<Root, Input>: Subscriber, Cancellable {
typealias Failure = Never
init(object: Root, keyPath: ReferenceWritableKeyPath<Root, Input>)
}
}
์ด Subscriber protocol์ ์ฑํํ์ฌ ๊ตฌํ๋์ด ์๋ ๋
์๋ค์ Combine์์ Subscrivers
๋ผ๋ enum์ ์ ์๋์ด ์๋ค. WWDC์์๋ ๊ทธ ์์ธ Assign
์ ๋ค๊ณ ์๋ค. Root๋ผ๋ Type์ Keypath์ ์ ์๋์ด ์๋ ํ์
์ด๋ค. KeyPath๋ฅผ ์ฐธ๊ณ ํ์.
์ด์ ์ด๋
์์ ๋ณด๋ฉด, Input Type์ผ๋ก ๊ฐ์ ๋ฐ์์ object๋ก ์ ์ธ๋์ด ์๋ Root Object์ ๊ทธ ๊ฐ์ keypath๋ฅผ ํตํด ์ฐพ์ ์ ์ฉํ๋ ์ญํ ์ ํ๊ณ ์๋ค. ๋จ์ํ ๊ฐ์ ์ฐ๋ ํ์๋ฅผ ํ๊ณ ์๊ณ , Swift๋ ์ด์ ํด๋น๋๋ Error๋ฅผ ๊ฐ์ง๊ณ ์์ง ์๊ธฐ ๋๋ฌธ์ Failure
๋ Never
ํ์
์ด๋ค.
The Pattern
๊ทธ๋ ๋ค๋ฉด ์ด๋ ์๋ค์ ์ค์ ๋ก๋ ์ด๋ป๊ฒ ํ์ฉํ ์ ์์๊น? ํ๋ฒ์ ์ถ๊ฐ๊ณผ ๊ตฌ๋ ์ด ์ด๋ฃจ์ด์ง๋ ๊ณผ์ ์ ํ๋ฒ ์์๋ณด์.
๋จผ์ Subscriber๋ Publisher์ Attach๋๋ค. ๊ทธ๋์ ์์ฑ๋ Subscriber๋ฅผ ์ธ์๋ก ๋ฃ์ด์ Publisher์๊ฒ ์ฃผ๋ ๊ฒ์ ์ ์ ์๋ค. ์ด ์์ฒญ์ ๋ฐ๊ฒ๋๋ฉด Publisher๋ Subscription์ด๋ผ๋ ๊ฐ์ฒด instance๋ฅผ ์ธ์๋ก ๋ด์์ ์ฃผ๊ฒ๋๋ค.(์ฆ, 1์์ ๋ฐ๋ Subscriber instance์ receive(subscription:)
ํจ์๋ฅผ ํธ์ถํ๋ ๊ฒ) ์ด Subscription ๊ฐ์ฒด๋ Subscirber๊ฐ Publisher๋ก๋ถํฐ ์ํ๋ ๊ฐ์ ์๊ตฌํ๊ฑฐ๋, ๊ตฌ๋
์ ์ทจ์ํ๋๋ฐ ์ฌ์ฉํ๋ค.
์ธํ
์ด ์๋ฃ๋๋ฉด Subscriber๋ Publisher์๊ฒ ์ํ๋ ๊ฐ์(๋ฌด์ ํ๋ ์์)๋งํผ์ request๋ฅผ ํ๊ฒ ๋๋ค. ๊ทธ ์๊ฐ ๋ถํฐ Publisher๋ ์์ฒญํ ๊ฐ์๋งํผ์ ๊ฐ, ํน์ ๊ทธ๋ณด๋ค ์ ์ ๊ฐ์๋ฅผ ๋ณด๋ธ๋ค. ๋ง์ฝ์ Publisher๊ฐ finiteํ๋ค๋ฉด, ์ต์ข
์ ์ผ๋ก subscriber์ receive(completion:)
ํจ์๋ฅผ ํธ์ถํ๊ณ ํต์ ์ด ์ข
๋ฃ๋๋ค.
Comeback to Wizard
// Using Publisher and Subscriber
class Wizard {
var grade: Int
}
let merlin = Wizard(grade: 5) // ๋ด๊ฐ ์ถ์ ํ๊ณ ์ถ์ Object๋ฅผ ๋ง๋ค๊ธฐ
let graduationPublisher = NotificationCenter.Publisher(center: .default, // Notification Center์ Predefined Publisher๋ฅผ ํ์ฉํด์ ์๋ฆผ ๋ฐ๊ธฐ
name: .graduated,
object: merlin)
let gradeSubscriber = Subscribers.Assign(object: merlin, keyPath: \.grade) // ๋ณ๊ฒฝ๋ ๊ฐ์ ๋ฐ์์ merlin๊ฐ์ฒด์ .grade property์ ๋ฐ์ํ๋ค.
graduationPublisher.subscribe(gradeSubscriber) // NOT WORKING!
Wizard์ ๊ด๋ จ๋ ์ฑ์ ๋ง๋ค๊ณ ์์๋ ๊ฒ์ ๋ ์ฌ๋ ค๋ณด์. Wizard๋ ํ๋ ์ ๊ฐ์ง๊ณ ์๊ณ , ํ๋ ์ด ๋์์ง์ ๋ฐ๋ผ ๊ฐ์ ๋ณ๊ฒฝํด ์ค๊ฒ์ด๋ค. Notification Center๊ฐ ์๋ก์ด ๊ฐ์ userInfo์ ๋ฃ์ด์ค ๊ฒ์ด๊ณ , ์ด๋ฅผ ๋ฐ์ํด์ฃผ๋ ์ฝ๋๋ฅผ ์ง๋ณด๋ ค๊ณ ํ๋ค.
์ผ๋จ์, ๋ด๊ฐ ์ถ์ ํ๊ณ ์ถ์ Object๋ฅผ ๋ง๋ค์ด ์ฃผ๊ณ , Notification Center์ Predefined Publisher๋ฅผ ํ์ฉํด์ ๋ณ๊ฒฝ๋ ์๋ฆผ์ ๋ฐ์๋ณด์. object๋ merlin์ผ๋ก ์ง์ ํ์ฌ, ํด๋น notification์ ์ ์กํ๋ ๊ฐ์ฒด๋ฅผ ๋ช ์ํด์ฃผ์.
Subscriber๋ ๊ฒฐ๊ณผ์ ์ผ๋ก ๊ฐ์ ๋ฐ์์ ๋ฐ์ํด์ฃผ์ด์ผ ํ๋, Assign
Subscriber๋ฅผ ๋ง๋ค์ด ์ฃผ๊ณ , ๋ฐ์ํ๊ณ ์ถ์ ๊ฐ์ฒด์ keypath๋ฅผ ์ธ์๋ก ๋ฃ์ด์ฃผ์.
์ด๋ ๊ฒ ํ๋ค subscribe๋ฅผ ํ๋ฉด ์๋ํ์ง ์๋๋ค. ์ด๋ ๋น์ฐํ๋ค. ์์์ Publisher์ Output, Failure Type๊ณผ Subscriber์ Input, Failure Type์ด ๋ง์์ผ ํ๋ค๊ณ ํ์๊ธฐ ๋๋ฌธ์ด๋ค. ์์์ Notification Center์ predefined Publisher์ Output Type์ ๋ดค์๋๋ฐ, Notification
์ด์๋ค. ๋ฐฉ๊ธ ๋ง๋ Subscriber์ ๊ฒฝ์ฐ Input Type์ด Int
์ด๋ค. KeyPath๊ฐ <Root(Wizard), Int>
๋ก ๋์ด์๊ธฐ ๋๋ฌธ์ด๋ค. (์์์ Assign<Root, Input>
์ด์๋๋ฐ, KeyPath์ ๋๋ฒ์งธ Type๊ณผ ๊ฐ์๋ค) ๊ฒฐ๊ตญ Type์ด ๋ง์ง ์์ Compile์ ์๋ฌ๊ฐ ๋๋ค.
Operators
์ด๋ฐ ์ํฉ์ด๋ผ๋ฉด ์ฐ๋ฆฌ๋ Publisher์ Subscriber ์ฌ์ด์ ๋ฌด์ธ๊ฐ ๋ณ๊ฒฝ์์ผ์ค ๊ฒ์ด ํ์ํ๋ค๋ ๊ฒ์ ์๊ฒ ๋๋ค. ๊ทธ๊ฒ Operator์ด๋ค.
Operator์ ํน์ง์ ๋ค์๊ณผ ๊ฐ๋ค.
- Publisher๋ฅผ ์ฑํ: ํ์๋ก ๊ฐ์ ๋ค์ ๋ณด๋ด์ผ ํ๊ธฐ ๋๋ฌธ
- ๊ฐ์ ๋ณํ๋ฅผ ์ํ ํ์๋ฅผ ๊ธฐ์
- Upstream์ผ๋ก Publisher๋ฅผ Subscribe
- Downstream์ผ๋ก Subscriber์๊ฒ ๊ฒฐ๊ณผ๋ฅผ ์ ๋ฌ
- Value Type: struct
extension Publishers {
struct Map<Upstream: Publisher, Output>: Publisher {
typealias Failure = Upstream.Failure
let upstream: Upstream
let transform: (Upstream.Output) -> Output
}
}
์ค์ ๋ก Operator๋ฅผ ๋ณด๋ฉด, Publishers
์๋์ ์ ์๋์ด ์๋ค. Publishers
๋ Subscribers
์ ๋ง์ฐฌ๊ฐ์ง๋ก Apple์์ ๊ธฐ๋ณธ ์ ๊ณตํ๋ ๋
์๋ค์ ๋ง๋ค์ด ๋ Enumeration Type์ด๋ค. Upstream์ผ๋ก Publisher Type์ ๋ฐ๊ณ , Output Type์ ๊ฐ๋๋ฐ. ์ด ๋์ ์ ์ฝ์ ์๋ฌด๊ฒ๋ ์๋ค. Publisher๋ฅผ returnํด๋ ๋ฌด๋ฐฉํ๋ค๋ ๋ง์ด๋ค. ๋จ, ์ฌ๊ธฐ์ Failure๋ upstream์ Failure type๊ณผ ๋์ผํ Type์ ๊ฐ์ ธ์ผ ํ๋ค.
// Using Publisher and Subscriber
class Wizard {
var grade: Int
}
let merlin = Wizard(grade: 5)
let graduationPublisher = NotificationCenter.Publisher(center: .default,
name: .graduated,
object: merlin)
let converter = Publishers.Map(upstream: graduationPublisher) { note in
return note.userInfo?["NewGrade"] as? Int ?? 0
}
let gradeSubscriber = Subscribers.Assign(object: merlin, keyPath: \.grade)
converter.subscribe(gradeSubscriber) // WORKING!
์ด์ ์์ ์๋๋ ๋
์์ ์๋ณด๋ฉด ์ด๋ ๊ฒ ๋๋ค. Publisher๋ฅผ ๋ฐ์์, ๊ฐ์ ๋ณํํด ์ค ๋ค, ์ํ๋ Output์ ๋ด๋ฑ๋๋ค. subscriber๋ graduationPublisher
๊ฐ ์๋ converter
์ Publisher์ ์ฐ๊ฒฐํด์ฃผ์ด์ผ ์ํ๋ ๊ฐ์ ๋ฐ์ ์
๋ฐ์ดํธํ ์ ์๋ค.
Operator Construction
ํ์ง๋ง ์ ๋ ๊ฒ ์ฐ๋ผ ๊ทธ๋ฌ๋ฉด ์๋ฌด๋ ์์ธ ๊ฒ ๊ฐ๋ค. ๊ทธ๋์ Apple์๋ ๊ธฐ๋ณธ์ ์ผ๋ก Publisher์ Operator๋ค์ ๋ง๋ค์ด ๋์๋ค.
extension Publisher {
func map<T>(_ transform: @escaping (Output) -> T) -> Publishers.Map<Self, T> {
return Publishers.Map(upstream: self, transform: transform)
}
}
Publisher ์ extension์ผ๋ก map
์ด๋ผ๋ ํจ์๋ฅผ ๋ง๋ค์ด๋์ด, Output์ ์ด๋ป๊ฒ ๋ณ๊ฒฝํ ์ง์ ๋ํด์๋ง ์์ฑํ๋ฉด, Publisher.Map
Operator๋ฅผ ๋ง๋ค์ด return ํด์ค๋ค.
๋ํ Subscriber๋ ๊ฐ๋จํ ๊ฒฝ์ฐ์๋ ๊ธฐ๋ณธ์ ์ผ๋ก Publisher ํ์ ์ extension์ผ๋ก ๊ตฌํ๋์ด ์๋ค.
let cancellable =
NotificationCenter.default.publisher(for: .graduated, object: merlin)
.map { note in
return note.userInfo?["NewGrade"] as? Int ?? 0
}
.assign(to: \.grade, on: merlin)
๊ทธ๋์ ๊ฒฐ๊ณผ์ ์ผ๋ก ์ฐ๋ฆฌ๊ฐ ๋ง์ด ์ฌ์ฉํ๋ ์ด๋ฐ ๋ชจ์์ด ๋์ค๊ฒ ๋๋ ๊ฒ์ด๋ค. ์ด์ ๋ช ํํ ์์๋ค!
Operator๋ ๊ต์ฅํ ๋ค์ํ๋ค. ์ด๊ฑธ ์ผ์ผํ ์ฒ์๋ถํฐ ๊ณต๋ถํ๊ธฐ ๋ณด๋ค๋, ์ ๋งํ ๊ฑด ์ ์๋์ด ์๋ค๊ณ ๊ฐ์ ํ๊ณ ์๊ฐ๋ ๋๋ง๋ค ์ฐพ์์ ์ตํ๋ ๊ฒ์ด ๊ฐ์ฅ ๋น ๋ฅธ ๋ฐฉ๋ฒ์ผ ๋ฏ ํ๋ค.
Future & Publisher
Apple์ Syncํ๊ฒ ์ฌ์ฉํ๋ Int์ Array๋ฅผ ๋๊ณ Future์ Publisher๋ฅผ ๋น๊ตํ๋ค. ๋๊ธฐ์ ์ผ๋ก Int๊ฐ์ ์ป๊ธฐ ์ํด์๋ Int, ์ฌ๋ฌ๊ฐ์ ์ํ๋ค๋ฉด Array๋ฅผ ์ฌ์ฉํ๋ค. ๊ทธ๋ฐ๋ฐ ๋ง์ฝ, ๋น๋๊ธฐ์ ์ผ๋ก. ์ฆ ํ์ ๊ฐ์ด ์๋ฃ๋ ์๊ธฐ์ ๊ฐ์ ๋ฐ๊ณ ์ถ์ ๊ฒฝ์ฐ์๋ ๋จ์ผ ๊ฐ์ ๊ฒฝ์ฐ future, ์ฌ๋ฌ ๊ฐ์ ๊ฒฝ์ฐ Publisher๋ฅผ ์ฌ์ฉํ๋ผ ํ๋ค.
Future์ ๊ฒฝ์ฐ, request ์์ ์ ํ๋ฒ์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ํ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ๋๋ฌธ์, ๊ทธ๋ฆฌ๊ณ Publsher์ ๊ฒฝ์ฐ N๋ฒ์ ๊ฐ์ ์๊ฐ์ ๊ฑธ์ณ ๋ฐ์ ์ ์๊ธฐ ๋๋ฌธ์ ์ด๋ฌํ ๋น์ ๋ฅผ ํ ๊ฒ์ด ์๋๊ฐ ํ๋ค.
๋ง๋ฌด๋ฆฌ
- Subscriber๋ Publisher์๊ฒ ๊ตฌ๋ ํ๊ฒ ๋ค๊ณ ์์ฒญํ๋ค.
- Publisher๋ Subscription์ ์ค๋ค. (๊ตฌ๋ ๊ถ!)
- ๊ตฌ๋
๊ถ์ ๊ตฌ๋
์ Life cycle์ ๊ด๋ฆฌํ๋ค. (์ฐ๋ฆฌ๊ฐ
AnyCancellable
๋ก ๋ฐ๋ ๋ ์์ด ์ด๋ ์.cancel()
์ด๋ผ๋ ๋ฉ์๋๋ก ๊ตฌ๋ ์ทจ์ ๊ฐ๋ฅ)
๊ฐ๋จํ๊ฒ Combine์ด ์ด๋ค ์๋ฆฌ๋ก ์๋๋๋์ง์ ๋ํด ์์๋ณด์๋ค. Future, ์ค์ ์ฌ์ฉ๋ฒ ๊ฐ์ด ์ธ ๊ธ์ด ๋ง์๋ฐ, ์ผ๋จ ์ค๋์ ์ฌ๊ธฐ์ ๋!