Deferred in Combine Framework

Manish Pathak
2 min readJun 26, 2023

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.

--

--