SlideShare a Scribd company logo
The Combine triad
The Combine triad
let publisher = URLSession.shared.dataTaskPublisher(for: someURLRequest)
let publisher = URLSession.shared.dataTaskPublisher(for: someURLRequest)
let sub = publisher.sink(receiveCompletion: { completionEvent in
print("The request finished with result: (completionEvent)")
}, receiveValue: { result in
print("Received result: (result)")
})
- Returns: A cancellable instance; used when you end assignment of the received value.
Deallocation of the result will tear down the subscription stream.
publisher.sink(receiveCompletion:receiveValue:)
Your code
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
Publisher
A Subscription is created
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
Publisher
A Subscription is created subscriber.receive(subscription)
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
Publisher
A Subscription is created subscriber.receive(subscription)
Subscriber Subscription
Request values from subscription
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
Publisher
A Subscription is created subscriber.receive(subscription)
Subscriber Subscription
Obtain valuesRequest values from subscription
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
Publisher
A Subscription is created subscriber.receive(subscription)
Subscriber Subscription
Obtain values
Send values
Request values from subscription
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
Publisher
A Subscription is created subscriber.receive(subscription)
Subscriber Subscription
Receive values and request more values
Obtain values
Send values
Request values from subscription
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
Publisher
A Subscription is created subscriber.receive(subscription)
Subscriber Subscription
Receive values and request more values
Obtain values
Send values
Send completion
Request values from subscription
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
Publisher
A Subscription is created subscriber.receive(subscription)
Subscriber Subscription
Receive values and request more values
Obtain values
Send values
Send completionReceive completion
Request values from subscription
Publishers
• Create subscriptions

• Link subscriptions to subscribers
Subscriptions
• Obtain values by generating them or receiving them.

• Relay obtained values to subscribers (if demand is high enough)
extension Publisher {
func dw_sink(receiveCompletion:
@escaping (Subscribers.Completion<Self.Failure>) -> Void,
receiveValue:
@escaping (Self.Output) -> Void) -> AnyCancellable {
}
}
dw_sink()
extension Publisher {
func dw_sink(receiveCompletion:
@escaping (Subscribers.Completion<Self.Failure>) -> Void,
receiveValue:
@escaping (Self.Output) -> Void) -> AnyCancellable {
let subscriber = DWSink(receiveValue: receiveValue,
receiveCompletion: receiveCompletion)
}
}
dw_sink()
extension Publisher {
func dw_sink(receiveCompletion:
@escaping (Subscribers.Completion<Self.Failure>) -> Void,
receiveValue:
@escaping (Self.Output) -> Void) -> AnyCancellable {
let subscriber = DWSink(receiveValue: receiveValue,
receiveCompletion: receiveCompletion)
self.subscribe(subscriber)
}
}
dw_sink()
extension Publisher {
func dw_sink(receiveCompletion:
@escaping (Subscribers.Completion<Self.Failure>) -> Void,
receiveValue:
@escaping (Self.Output) -> Void) -> AnyCancellable {
let subscriber = DWSink(receiveValue: receiveValue,
receiveCompletion: receiveCompletion)
self.subscribe(subscriber)
return AnyCancellable(subscriber)
}
}
dw_sink()
public protocol Subscriber : CustomCombineIdentifierConvertible {
associatedtype Input
associatedtype Failure : Error
func receive(subscription: Subscription)
func receive(_ input: Self.Input) -> Subscribers.Demand
func receive(completion: Subscribers.Completion<Self.Failure>)
}
class DWSink<Input, Failure: Error>: Subscriber, Cancellable {
let receiveValue: (Input) -> Void
let receiveCompletion: (Subscribers.Completion<Failure>) -> Void
func receive(subscription: Subscription) {
// todo: implement
}
func receive(_ input: Input) -> Subscribers.Demand {
// todo: implement
}
func receive(completion: Subscribers.Completion<Failure>) {
// todo: implement
}
func cancel() {
// todo: implement
}
}
var subscription: Subscription?
func receive(subscription: Subscription) {
subscription.request(.unlimited)
self.subscription = subscription
}
DWSink.receive(subscription:)
var subscription: Subscription?
func receive(subscription: Subscription) {
subscription.request(.unlimited)
self.subscription = subscription
}
DWSink.receive(subscription:)
.max(value:) .none
func receive(_ input: Input) -> Subscribers.Demand {
receiveValue(input)
return .none
}
DWSink.receive(_:)
receive(subscription:)
Request: .max(1)
Total demand: 1
receive(subscription:)
Request: .max(1)
Total demand: 1
receive(_:)
Return: .max(5)
Total demand: 6
receive(subscription:)
Request: .max(1)
Total demand: 1
receive(_:)
Return: .max(5)
Total demand: 6
receive(_:)
Return: .none
Total demand: 6
func receive(completion: Subscribers.Completion<Failure>) {
receiveCompletion(completion)
}
DWSink.receive(completion:)
func cancel() {
subscription = nil
}
DWSink.cancel()
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
Publisher
A Subscription is created subscriber.receive(subscription)
Subscriber Subscription
Receive values and request more values
Obtain values
Send values
Send completionReceive completion
Request values from subscription
let publisher = URLSession.shared.dataTaskPublisher(for: someURLRequest)
let cancellable = publisher.dw_sink(receiveCompletion: { completion in
print("Custom chain completed: (completion)")
}, receiveValue: { result in
print("Custom chain got result: (result)")
})
let publisher = URLSession.shared.dataTaskPublisher(for: someURLRequest)
let cancellable = publisher.dw_sink(receiveCompletion: { completion in
print("Custom chain completed: (completion)")
}, receiveValue: { result in
print("Custom chain got result: (result)")
})
⚠
public protocol Publisher {
associatedtype Output
associatedtype Failure : Error
func receive<S>(subscriber: S)
where S: Subscriber, Self.Failure == S.Failure, Self.Output == S.Input
}
struct DWDataTaskPublisher: Publisher {
typealias Failure = URLError
typealias Output = (data: Data, response: URLResponse)
let request: URLRequest
func receive<S: Subscriber>(subscriber: S)
where Failure == S.Failure, Output == S.Input {
}
}
struct DWDataTaskPublisher: Publisher {
typealias Failure = URLError
typealias Output = (data: Data, response: URLResponse)
let request: URLRequest
func receive<S: Subscriber>(subscriber: S)
where Failure == S.Failure, Output == S.Input {
let subscription = DWDataTaskSubscription<S>(request: request,
subscriber: subscriber)
}
}
struct DWDataTaskPublisher: Publisher {
typealias Failure = URLError
typealias Output = (data: Data, response: URLResponse)
let request: URLRequest
func receive<S: Subscriber>(subscriber: S)
where Failure == S.Failure, Output == S.Input {
let subscription = DWDataTaskSubscription<S>(request: request,
subscriber: subscriber)
subscriber.receive(subscription: subscription)
}
}
public protocol Subscription : Cancellable, CustomCombineIdentifierConvertible {
func request(_ demand: Subscribers.Demand)
}
class DWDataTaskSubscription<S: Subscriber>: Subscription
where S.Failure == URLError,
S.Input == (data: Data, response: URLResponse) {
var subscriber: S?
let request: URLRequest
func request(_ demand: Subscribers.Demand) {
// todo: implement
}
func cancel() {
subscriber = nil
}
}
func request(_ demand: Subscribers.Demand) {
guard demand > 0 else { return }
URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error as? URLError {
self.subscriber?.receive(completion: .failure(error))
} else if let data = data, let response = response {
self.subscriber?.receive((data, response))
self.subscriber?.receive(completion: .finished)
}
self.cancel()
// if we don't have an error AND no data, we should maybe do something.
// but we'll ignore it for now.
}.resume()
}
func request(_ demand: Subscribers.Demand) {
guard demand > 0 else { return }
URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error as? URLError {
self.subscriber?.receive(completion: .failure(error))
} else if let data = data, let response = response {
self.subscriber?.receive((data, response))
self.subscriber?.receive(completion: .finished)
}
self.cancel()
// if we don't have an error AND no data, we should maybe do something.
// but we'll ignore it for now.
}.resume()
}
let publisher = URLSession.shared.dataTaskPublisher(for: someURLRequest)
let cancellable = publisher.dw_sink(receiveCompletion: { completion in
print("Custom chain completed: (completion)")
}, receiveValue: { result in
print("Custom chain got result: (result)")
})
let publisher = URLSession.shared.dataTaskPublisher(for: someURLRequest)
let cancellable = publisher.dw_sink(receiveCompletion: { completion in
print("Custom chain completed: (completion)")
}, receiveValue: { result in
print("Custom chain got result: (result)")
})
let publisher = DWDataTaskPublisher(request: someURLRequest)
publisher.sink(receiveCompletion:receiveValue:)
Your code
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
Publisher
A Subscription is created
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
Publisher
A Subscription is created subscriber.receive(subscription)
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
Publisher
A Subscription is created subscriber.receive(subscription)
Subscriber Subscription
Request values from subscription
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
Publisher
A Subscription is created subscriber.receive(subscription)
Subscriber Subscription
Obtain valuesRequest values from subscription
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
Publisher
A Subscription is created subscriber.receive(subscription)
Subscriber Subscription
Obtain values
Send values
Request values from subscription
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
Publisher
A Subscription is created subscriber.receive(subscription)
Subscriber Subscription
Receive values and request more values
Obtain values
Send values
Request values from subscription
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
Publisher
A Subscription is created subscriber.receive(subscription)
Subscriber Subscription
Receive values and request more values
Obtain values
Send values
Send completion
Request values from subscription
publisher.sink(receiveCompletion:receiveValue:)
Your code
Sink
A Subscriber is created Publisher.subscribe(_:)
Publisher
A Subscription is created subscriber.receive(subscription)
Subscriber Subscription
Receive values and request more values
Obtain values
Send values
Send completionReceive completion
Request values from subscription
Some tips and advise
• I mentioned it a couple of times but Apple does not recommend that you
implement custom publishers and subscriptions

• That said, it’s good to explore and see how things work.

• Retain your AnyCancellable because a in correct implementation,
Subscription will cancel as soon as the AnyCancellable is released
Thank you

More Related Content

PDF
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
PDF
A Series of Fortunate Events - Symfony Camp Sweden 2014
PDF
A Series of Fortunate Events - PHP Benelux Conference 2015
PPTX
AngularJS, More Than Directives !
PDF
2 years after the first event - The Saga Pattern
PDF
Design how your objects talk through mocking
PPTX
How to perform debounce in react
PDF
Combine Framework
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - PHP Benelux Conference 2015
AngularJS, More Than Directives !
2 years after the first event - The Saga Pattern
Design how your objects talk through mocking
How to perform debounce in react
Combine Framework

Similar to The combine triad (20)

PPTX
Combine in iOS - Basics
PDF
Rethinking Syncing at AltConf 2019
PDF
Promise of an API
PDF
Maintaining a dependency graph with weaver
PDF
ReactiveCocoa and Swift, Better Together
PDF
A Tour of Combine
PDF
async/await in Swift
PDF
Kitura Todolist tutorial
PDF
URLProtocol
PDF
Taming Core Data by Arek Holko, Macoscope
PDF
Mobile Fest 2018. Александр Корин. Болеутоляющее
PDF
Introduction to reactive programming & ReactiveCocoa
PDF
Protocol-Oriented Networking
PPTX
Apple.combine
PDF
Implementing pseudo-keywords through Functional Programing
PDF
Developing iOS REST Applications
PDF
Taming Cloud APIs with Swift
PDF
Firebase & SwiftUI Workshop
PDF
Distributing information on iOS
PDF
From android/java to swift (3)
Combine in iOS - Basics
Rethinking Syncing at AltConf 2019
Promise of an API
Maintaining a dependency graph with weaver
ReactiveCocoa and Swift, Better Together
A Tour of Combine
async/await in Swift
Kitura Todolist tutorial
URLProtocol
Taming Core Data by Arek Holko, Macoscope
Mobile Fest 2018. Александр Корин. Болеутоляющее
Introduction to reactive programming & ReactiveCocoa
Protocol-Oriented Networking
Apple.combine
Implementing pseudo-keywords through Functional Programing
Developing iOS REST Applications
Taming Cloud APIs with Swift
Firebase & SwiftUI Workshop
Distributing information on iOS
From android/java to swift (3)
Ad

More from Donny Wals (15)

PDF
Your 🧠 on Swift Concurrency
PDF
Using Combine, SwiftUI and callAsFunction to build an experimental localizati...
PDF
Building reusable components with generics and protocols
PDF
Adopting tdd in the workplace
PDF
The Testing Games: Mocking, yay!
PDF
Me and my importers
PDF
JSON and Swift, Still A Better Love Story Than Twilight
PDF
Adopting tdd in the workplace
PDF
In Defense Of Core Data
PDF
Effectively Producing And Shipping Frameworks For Multiple Platforms
PDF
Improving apps with iOS 10 notifications (do iOS 2016)
PDF
Talk - git task managers and ci
PDF
Developing in the Fastlane -> How LookLive uses Fastlane to automate and spee...
PDF
Marketing strategie Arto
KEY
Hoorcollege Flash 9-2-2012
Your 🧠 on Swift Concurrency
Using Combine, SwiftUI and callAsFunction to build an experimental localizati...
Building reusable components with generics and protocols
Adopting tdd in the workplace
The Testing Games: Mocking, yay!
Me and my importers
JSON and Swift, Still A Better Love Story Than Twilight
Adopting tdd in the workplace
In Defense Of Core Data
Effectively Producing And Shipping Frameworks For Multiple Platforms
Improving apps with iOS 10 notifications (do iOS 2016)
Talk - git task managers and ci
Developing in the Fastlane -> How LookLive uses Fastlane to automate and spee...
Marketing strategie Arto
Hoorcollege Flash 9-2-2012
Ad

Recently uploaded (20)

PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
Modernizing your data center with Dell and AMD
PDF
Encapsulation theory and applications.pdf
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
DOCX
The AUB Centre for AI in Media Proposal.docx
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PPTX
MYSQL Presentation for SQL database connectivity
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PPTX
Cloud computing and distributed systems.
PDF
KodekX | Application Modernization Development
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Empathic Computing: Creating Shared Understanding
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
cuic standard and advanced reporting.pdf
PDF
NewMind AI Weekly Chronicles - August'25 Week I
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Modernizing your data center with Dell and AMD
Encapsulation theory and applications.pdf
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
The AUB Centre for AI in Media Proposal.docx
20250228 LYD VKU AI Blended-Learning.pptx
Review of recent advances in non-invasive hemoglobin estimation
Advanced methodologies resolving dimensionality complications for autism neur...
MYSQL Presentation for SQL database connectivity
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Cloud computing and distributed systems.
KodekX | Application Modernization Development
“AI and Expert System Decision Support & Business Intelligence Systems”
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Empathic Computing: Creating Shared Understanding
Encapsulation_ Review paper, used for researhc scholars
cuic standard and advanced reporting.pdf
NewMind AI Weekly Chronicles - August'25 Week I

The combine triad