Deferred in Combine Framework
In the previous article, we saw how Future
processes.
we know that the Future
began its processing as soon as it is created. If we wrap the same code with Deferred
, Deferred
won’t even create the Future
until there is a subscription.
we can see how this defers any processing until a subscription happens.
let deferredPublisher = Deferred {
Deferred {
Future<Int, Never> { promise in
print("🔮 Future began processing")
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
let number = Int.random(in: 1...10)
print("🔮 Future emitted number: \(number)")
promise(Result.success(number))
}
}.print("🔍 Publisher event")
}
}
Deferred
won’t even create the Future
until there is a subscription.
Let’s add a subscriber.
let deferredPublisher = Deferred {
Deferred {
Future<Int, Never> { promise in
print("🔮 Future began processing")
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
let number = Int.random(in: 1...10)
print("🔮 Future emitted number: \(number)")
promise(Result.success(number))
}
}.print("🔍 Publisher event")
}
}
deferredPublisher
.sink { print ("🎧 Future stream received: \($0)") }
.store(in: &cancellables)
Now we get the same logs as when we created the Future
without Deferred
, but only because we have a definitive subscriber.
🔮 Future began processing
🔍 Publisher event: receive subscription: (Future)
🔍 Publisher event: request unlimited
🔮 Future emitted number: 7
🔍 Publisher event: receive value: (7)
🎧 Future stream received: 7
🔍 Publisher event: receive finished
Deferred
with multiple subscribers
Let’s subscribe two subscribers to the same deferred publisher.
deferredPublisher
.sink { print ("🎧 Future stream 1 received: \($0)") }
.store(in: &cancellables)
deferredPublisher
.sink { print ("🎧 Future stream 2 received: \($0)") }
.store(in: &cancellables)
Here are the logs we get now.
🔮 Future began processing
🔍 Publisher event: receive subscription: (Future)
🔍 Publisher event: request unlimited
🔮 Future began processing
🔍 Publisher event: receive subscription: (Future)
🔍 Publisher event: request unlimited
🔮 Future emitted number: 9
🔍 Publisher event: receive value: (9)
🎧 Future stream 1 received: 9
🔍 Publisher event: receive finished
🔮 Future emitted number: 6
🔍 Publisher event: receive value: (6)
🎧 Future stream 2 received: 6
🔍 Publisher event: receive finished
Notice that the emitted events are different.
Each subscription makes the DeferredPublisher
run its closure that creates a Future
. Therefore each subscription gets a different Future
and therefore a different emitted event.
Conclusion
Future
acts like a promise to return some value in the future. It can also fail. It’s useful for creating publishers of one-time asynchronous events. We need to be conscious that Future
does its processing as soon as it is created.
Deferred
wraps the creation of any type of publisher and only creates the publisher when a subscriber is present. Used with Future
deferred can defer the Future
’s work until downstream subscribers are present.