-
(Combine) Publisher, Subscriber + SubjectiOS💖 2024. 10. 1. 21:11
컴바인 부져버리겠어
Publisher

Publisher - Output type, 실패 type 정의 필요
- Built-in Publisher
- Just : 값을 다룸
- Future : Function을 다룸
- Publisher 을 자동으로 제공해주는 기능들 (iOS에서)
- Timer
- URLSession.dataTask
- NotificationCenter
let justPublisher = Just(1000) let subscription = justPublisher.sink { value in print("received value: \(value)") } // received value: 1000let arrPublisher = [1, 2, 3, 4].publisher let subscription = arrPublisher.sink { value in print("received value: \(value)") } // received value: 1 // received value: 2 // received value: 3 // received value: 4URLSession.dataTask 코드 예시 )
// URLSessionTask : server에서 데이터를 받는 코드를 구현하는데 사용되는 객체 struct SomeDecodable: Decodable {} URLSession.shard.dataTaskPublisher(for: URL(string: "https://www.google.com")!) .map { data, response in return data } .decode(type: SomeDecodable.self, decoder: JSONDecoder()) // server에서 받은 데이터를 앱 내의 객체형으로 decoding 해줌Notifications 코드 예시 )
let center = NotificationCenter.default let noti = Notification.Name("MyNoti") let notiPublisher = noti.publisher(for: noti, object: nil) let subscription = notiPublisher.sink { _ in print("Received Notification") } center.post(for: noti, object: nil) center.post(for: noti, object: nil) subscription.cancel() // Received Notification // Received NotificationKeyPath binding to NSObject instances 코드 예시 )
let ageLalbe = UILable() // UILable: NSObject print("lable text: \(ageLable.text)") Just(28) .map { "Age is \($0)" } .assign(to: \.text, on: ageLable) print("lable text: \(ageLable.text)") // lable text: nil // lable text: Optional("Age is 28")Timer 코드 예시 )
// 1초마다, main thread에서, common(보통) 방법으로 // 해당 publisher을 구독했을때, 알아서 타이머가 동작해라! let timer = Timer .publish(every: 1, on: .main, in: .common) .autoconnect() let timerSubscription = timer.sink { time in print("time: \(time)") } // 초반의 5초 후에 execute구문 실행 DispatchQueue.main.asyncAfter(deadline: .now() + 5) { timerSubscription.cancel() } // time: 2024-10-04 09:15:46 +0000 // time: 2024-10-04 09:15:47 +0000 // time: 2024-10-04 09:15:48 +0000 // time: 2024-10-04 09:15:49 +0000 // time: 2024-10-04 09:15:50 +0000Subscriber

Subscriber - Publisher에게 데이터를 요청
- Input type, 실패 type 정의 필요
- Built-in subscriber
- assign : publisher가 제공하는 데이터를 특정 객체의 key-path에 할당
- sink : publisher가 제공하는 데이터를 받는 클로져를 제공
코드 예시)
데이터 제공해주는 arrPublisher에 assign subscriber로 붙었는데, 그 데이터를 object라는 객체의 property라는 프로퍼티에 할당
let arrPublisher = [1, 2, 3, 4].publisher class combineClass { var property: Int = 0 { didSet { print("Did set property to \(property)") } } } let object = combineClass() let subscription = arrPublisher.assign(to: \.property, on: object) // (subscriber) to: key-path, on: object print("Final value: \(object.property)") // object > property > didSet의 구문 > print("Final value: \(object.property)") // Did set property to 1 // Did set property to 2 // Did set property to 3 // Did set property to 4 // Final value: 4
Publisher & Subscriber Pattern

Publisher-Subscriber Pattern - 컴바인 : 효율적인 비동기처리 방식
- publisher 라는 a.k.a 생성자, 크리에이터
= 서버에 연결되어 데이터 뿜는 역할- '서버에 연결되어 받게되는 데이터' 를 받기위해 연결되어야 하는데
그래서 subscriber 이, publisher 에게 붙는다.
- '서버에 연결되어 받게되는 데이터' 를 받기위해 연결되어야 하는데
Subscription
- subscriber와 publisher가 연결됨을 나타내는 존재
- Cancellable protocol 을 준수한다.
- 따라서, subscription을 통해 연결을 cancel 할 수 있다
* print() 함수
모든 publishing events의 로그 메세지를 프린팅 해주는 메소드

let subject = PassthroughSubject<String, Never>() let subscription = subject .print("[Debug]") .sink { value in print("Subscriber received value: \(value)") } subject.send("Hi") subject.send("How are you?") subject.send("I'm good.") subject.cancel() //[Debug]: receive subscription: (PassthroughSubject) //[Debug]: request unlimited //[Debug]: receive value: (Hi) Subscriber received value: Hi //[Debug]: receive value: (How are you?) Subscriber received value: How are you? //[Debug]: receive value: (I'm good.) Subscriber received value: I'm good. //[Debut]: received finishedSubject (Publisher)
- send()를 통해 이벤트 주입시킬 수 있는 Publisher
- 기존 비동기처리 방식에서 Combine 으로 전환시 유용!!
This can be useful for adapting existing imperative code to the Combine model. - PassthroughSubject
- Subscriber에게 값을 전달할 뿐
- 전달한 값 들고있지 X
- CurrentValueSubject
- 초기값 필수
- 최근(직전)에 받은 데이터를 들고있는다.
- 새로운 데이터를 받으면, 직전에 들고있던 데이터를 output하고, 새로 받은 데이터도 배출한다.
코드 예시)
// PassthroughSubject let publisher = PassthroughSubject<String, Never>() let subscription = publisher.sink { value in // sink : built-in subscriber print("subscription received value: \(value)") } publisher.send("Hello!") // subscription received value: Hello!// CurrentValueSubject // 초기값 필수! let publisher = CurrenrValueSubject<String, Never>("ABC") publisher.send("data1") let subscription = publisher.sink { value in print("subsciption received value: \(value)") } publisher.send("data2") // subscription received value: data1 // 1. 이전값을 버려준다(= 버린다 = output) // subscription received value: data2 // 2. 현재주입된 값@ Published (Publisher)
- @Published 로 선언된 property를 publisher로 만들어줌
- Class 내에서만! 사용 가능
- $ 를 사용하여 publisher에 접근 가능
class Battery { @Published var battery: Int init(battery: Int) { self.battery = battery } } let phoneBattery = Battery(battery: 100) let subscription = phoneBattery.$battery.sink { print("Battery now: \($0)") } phoneBattery.battery = 20 // Battery now: 100 // Battery now: 20https://hortenssiaa.tistory.com/31
(Combine) Scheduler, Operator
컴바인 부져버리겠어 Scheduler언제, 어떻게 클로저가 실행되는지 결정해준다. (프로토콜이다)A protocol that defines when and how to execute a closure.Operator의 파라미터로 scheduler를 받을때가 있다. scheduler로
hortenssiaa.tistory.com
출처)
- https://developer.apple.com/videos/play/wwdc2019/722/
Introducing Combine - WWDC19 - Videos - Apple Developer
Combine is a unified declarative framework for processing values over time. Learn how it can simplify asynchronous code like networking,...
developer.apple.com
- 왕초보를 위한, 한 번에 끝내는 iOS 앱 개발 바이블
- https://developer.apple.com/documentation/combine/publisher/assign(to:on:)
'iOS💖' 카테고리의 다른 글
(Swift) mutating (1) 2024.10.11 (Combine) Scheduler, Operator (3) 2024.10.07 (Combine) 소개 (1) 2024.09.30 (Swift) NSCollectionLayoutGroup. vertical / horizontal method 종류 (2) 2024.09.26 (Swift) Collection Reusable View 사용 (0) 2024.09.26