How to make receive(on:) deliver value immediately if already on the correct scheduler?

Please consider this code:

import Combine

class TestViewModel: ObservableObject {
    
    @Published public var value: Int?

    var cancellable: AnyCancellable?

    init() {
        cancellable = Just(1)
            .receive(on: DispatchQueue.main)
            .assign(to: \.value, on: self)
    }
}

As is when TestViewModel is created on the main thread self.value isn't assigned to until sometime after the init function exits. This means SwiftUI does two draws one for value == nil and one for value == 1.

Is there a way to make receive(on:) deliver the value immediately when called from the same scheduler (DispatchQueue.main in this case) instead of having it queued?

I've come up with this and it seems to do what I want:

extension Publisher {
    public func receiveImmediatelyOnMain() -> AnyPublisher<Self.Output, Self.Failure> {
        return self.flatMap({ value -> AnyPublisher<Self.Output, Self.Failure> in
            if Thread.isMainThread {
                return Just(value)
                    .setFailureType(to: Self.Failure.self)
                    .eraseToAnyPublisher()
            } else {
                return Just(value)
                    .setFailureType(to: Self.Failure.self)
                    .receive(on: DispatchQueue.main)
                    .eraseToAnyPublisher()
            }
        }).eraseToAnyPublisher()
    }
}

Look good? Is there a better implementation out there somewhere?

Thanks,
Jesse

Terms of Service

Privacy Policy

Cookie Policy