Lets say I want to create an asynchronous function that calls some random API and returns a random Int. I want wrap it using a future
func createFuture() -> Future<Int, Never> {
return Future { promise in
promise(.success(Int.random(1...10))
}
}
This would return me the same output everytime. Instead i want to return AnyPublisher.
func createAnyPublisher() -> AnyPublisher<Int, Never> { //This is invalid
return AnyPublisher<Int, Never> { seed in
seed.success(Int.random(in: 1...10))
}
}
A better example:
func guessNumber(num: Int) -> AnyPublisher<Bool, Never> {
asyncRandomNumber { winner in
if num == winner {
// return true
} else {
// return false
}
}
}
private func asyncRandomNumber(completion: (Int) -> Void) {
completion(Int.random(in: 1...10))
}
How do you wrap that asyncRandomNumber ?
Future
caches its result at initialisation, that's why you always see the same result. You can use Just
instead if you want each subscriber to receive a different random number.
func randomIntPublisher() -> AnyPublisher<Int, Never> {
Just(Int.random(in: 1...10)).eraseToAnyPublisher()
}
If you want to wrap an async function in a Publisher
, you can use Future
, just make sure you call your function each time before creating a new subscription - this will make sure that you create a new Future
and hence the result won't be cached and shared between the different subscribers.
func asyncRandomNumber(completion: @escaping (Int) -> Void) {
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
completion(Int.random(in: 1...100))
}
}
func asyncRandomNumber() -> AnyPublisher<Int, Never> {
Future { promise in
asyncRandomNumber(completion: { num in
promise(.success(num))
})
}.eraseToAnyPublisher()
}
asyncRandomNumber().sink(receiveValue: { print("First subscription received \($0)") }).store(in: &subscriptions)
asyncRandomNumber().sink(receiveValue: { print("Second subscription received \($0)") }).store(in: &subscriptions)