I have an extension which takes a publisher and waits until a non-nil value is published before taking its value and returning it for use as an async/await function.
extension Publisher {
func value() async throws -> Output {
try await self
.compactMap { $0 }
.eraseToAnyPublisher()
.async()
}
}
enum AsyncError: Error {
case finishedWithoutValue
}
extension AnyPublisher {
/// Returns the first value of the publisher
@discardableResult
func async() async throws -> Output {
try await withCheckedThrowingContinuation { continuation in
var cancellable: AnyCancellable?
var finishedWithoutValue = true
cancellable = first()
.sink { result in
switch result {
case .finished:
if finishedWithoutValue {
continuation.resume(throwing: AsyncError.finishedWithoutValue)
}
case let .failure(error):
continuation.resume(throwing: error)
}
cancellable?.cancel()
} receiveValue: { value in
finishedWithoutValue = false
continuation.resume(with: .success(value))
}
}
}
}
For some reason, when I use it on an optional @Published value, it returns an optional, rather than returning the unwrapped value of it. Since it waits until a non-nil value returns, why isn't it unwrapping it? For example, assuming foo is an optional published value:
let one = await $foo.value() // Returns an optional
let two = await $foo.compactMap { $0 }.value() // Returns a non-optional
How do I fix this?