Combine(1)에서 간단히 정의한 Publisher / Subscriber / Operator
1️⃣ Publisher
- 생산자
2️⃣ Subscriber
- 소비자
3️⃣ Operator
- 가공자
Event Stream(Event Pipeline)
- Publisher → Operator → Subsciber
- 위와 같은 순서에서 어떠한 이벤트들이 생길지 모르니, Combine이라는 비동기 Framework가 필요함!
더 자세히 알아보자!
1️⃣ Publisher
protocol Publisher {
associatedtype Output // 구체적인 Output 정의
associatedtype Failure: Error // 구체적인 Failure 정의
func subscribe<S: Subscriber>(_ subscriber: S)
where S.Input == Output, S.Failure == Failure
}
- 데이터를 배출하는 친구
- 구체적인 output 및 실패타입을 정의
- Subscriber가 요청한 것 만큼 데이터를 제공 - 빌트인 Publisher인 Just, Future가 있음
- Just : 값을 다룸
- Future : Function을 다룸 - iOS에서 자공으로 제공해주는 녀석들
- NotificationCenter
- Timer
- URLSession.dataTask
2️⃣ Subscriber
protocol Subscriber {
associatedtype Input
associatedtype Failure: Error
func receive(subscription: Subscription)
func receive(_ input: Input) -> Subscribers.Demand
func receive(completion: Subscribers.Completion<Faliure>)
}
- Publisher에게 데이터 요청
- Input, Failure 타입 정의 필요
- Publisher 구독 후, 갯수 요청
- 파이프라인 취소 가능
- 빌트인 Subscriber인 assign, sink
- assign : Publisher가 제공한 데이터를 특정 객체의 키패스에 할당
- sink : Publisher가 제공한 데이터를 받을 수 있는 클로저를 제공
👀 Subscriber & Publisher Pattern
- Subscriber 는 Publisher에 붙게 됨
- Publisher는 하나의 Subscription을 보냄
- Subscriber는 N개의 values를 요청함
- Publisher는 N개의 values를 보내거나 보내지 않는다.
- Publisher는 completion을 보낸다.
👀 여기서, Subscription ?!
- Subscriber가 Publisher와 연결됨을 나타냄
- Publisher가 발행한 구독 티켓
- 이 티겟으로 데이터를 받을 수 있고
- 티켓이 사라지면, 구독관계도 사라짐 - Cancellable protocol을 따르고 있음
- 따라서, Subscription을 통해 연결을 Cancel 할 수 있음
📌 Publisher의 일종인, Subject와 @Published
1️⃣ Subject
- send(_:) 메소드를 이용해서 이벤트 값을 주입시킬 수 있는 Publisher
- 기존의 비동기처리 방식에서 Combine으로 전환 시 유용!
- 2가지 빌트인 타입
1. PassthroughSubject
- Subscriber가 달라고 요청하면, 그때부터 받은 값을 전달해주기만 함 → 가장 최근에 전달한 값을 들고 있지 않음
2. CurrentValueSubject
- Subscriber가 달라고 요청하면, 최근에 가지고 있던 값을 전달하고, 그때부터 받은 값을 전달 → 가장 최근에 전달한 값을 들고 있음
2️⃣ @Published
- @Published로 선언된 Property를 Publisher로 만들어줌
- 클래스에 한해서 사용됨 (구조체에서 사용 X)
- $을 이용해서 Publisher에 접근 가능
class Weather {
@Published var temperature: Double
init(temperature: Double) {
self.temperature = temperature
}
}
let weather = Weather(temperature: 20)
let subscription = weather.$temperature.sink {
print("Temperature now: \($0)")
}
weather.temperature = 25
// Temperature now: 20.0
// Temperature now: 25.0
→ @Published 로 선언된 temperature Property가 Publisher가 된다.
→ sink 를 통해, temperature의 값이 바뀔 때마다 print문을 호출할 수 있게 된다.
3️⃣ Operator
- Publisher에게 받은 값을 가공해서 Subscriber에게 제공
- Input, Output, Failure type을 받는데 타입이 다를 수 있음
- 많은 빌트인 Operator! : map, filter, reduce, collect, combineLatest ...
Scheduler
- 언제, 어떻게 Closer을 실행할 지 정해줌
- Operatoer에서 Scheduler를 파라미터로 받을 때가 있음
- 따라서, 작업에 따라 백그라운드 혹은 메인스레드에서 작업이 실행될 수 있게 도와줌 - Scheduler가 스레드 자체는 아니다!
2가지 Scheduer 메소드
1️⃣ subscribe(on:)
- Publisher가 어느 스레드에서 수행할 지 결정해줌
- 무거운 작업은 메인스레드가 아닌 다른 스레드에서 작업할 수 있도록 도와줌
- ex) 백그라운드 계산이 많이 필요한 것
- ex) 파일 다운로드해야하는 경우
2️⃣ receive(on:)
- Operator, Subscriber가 어느 스레드에서 수행할 지 결정해줌
- UI업데이트에 필요한 데이터를 메인스레드에서 받을 수 있게 도와줌
- ex) 서버에서 가져온 데이터로 UI업데이트를 할 때
Scheduler의 일반적인 패턴
let jsonPublisher = MyJSONLoaderPubliser() // Some publisher.
jsonPublisher.subscribe(on: backgroundQueue)
.receive(on: RunLoop.main)
.sink{ value in
label.text = value
}
→ backgroundQueue에서 Publisher가 수행되게 함
→ Operator, Subscriber 가 main thread에서 수행되게 함
🍎 UI 업데이트 시, Apple이 지향하는 방식
🚫 지양
pub.sink {
DispatchQueue.main.async {
// Do update ui
}
}
// 업데이트가 되긴 됨.
✅ 지향
pub.receive(on: DispatchQueue.main).sink {
// Do update ui
}
💡 Combine 실습 코드는 Combine Practice 폴더에서 확인할 수 있다!
https://github.com/yexjin/iOS_Study
Reference
- 패스트 캠퍼스
'iOS' 카테고리의 다른 글
[iOS] iOS에서의 네트워크 (0) | 2022.07.14 |
---|---|
[iOS] 네트워크 왕 기초 개념 (0) | 2022.07.14 |
[iOS] Combine (1) : Overview (0) | 2022.07.03 |
[iOS] Navigation과 Modal (0) | 2022.06.29 |
[iOS] Diffable DataSource, SnapShot, Compositional Layout (0) | 2022.06.04 |