iOS

[iOS] Combine (2) : Publisher / Subscriber / Operator

yevdev 2022. 7. 3. 16:49

 

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

Pattern

  1. Subscriber 는 Publisher에 붙게 됨
  2. Publisher는 하나의 Subscription을 보냄 
  3. Subscriber는 N개의 values를 요청함
  4. Publisher는 N개의 values를 보내거나 보내지 않는다.
  5. 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

 

GitHub - yexjin/iOS_Study: 온라인 강의를 수강하며 진행한 iOS 토이프로젝트 모음집📱

온라인 강의를 수강하며 진행한 iOS 토이프로젝트 모음집📱. Contribute to yexjin/iOS_Study development by creating an account on GitHub.

github.com

 

 


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