Make custom Publisher run on a different DispatchQueue on Swift Combine
Asked Answered
A

3

18

I created a function that returns a custom Publisher in Swift Combine using the code below:

func customPubliher() -> AnyPublisher<Bool, Never> {
    return Future<Bool, Never> { promise in
        promise(.success(true))
    }.eraseToAnyPublisher()
}

Then I subscribed to this publisher using the following code:

customPublisher()
    .subscribe(on: DispatchQueue.global())
    .map { _ in
        print(Thread.isMainThread)
    }
    .sink(receiveCompletion: { _ in }, receiveValue: { value in
        // Do something with the value received
    }).store(in: &disposables)

But even though I added the line .subscribe(on: DispatchQueue.global()) when I do the subscription, the code is not executed in a different queue (the print in the .map outputs true).

However, if I replace my custom publisher for one of built-in Combine publishers, for example Just() (see below), the same code is executed fine on a different queue:

Just(true)
    .subscribe(on: DispatchQueue.global())
    .map { _ in
        print(Thread.isMainThread)
    }
    .sink(receiveCompletion: { _ in }, receiveValue: { value in
        // Do something with the value received
    }).store(in: &disposables)

The .map on the code above outputs false.

What am I doing wrong when I use my custom publisher? I want it to run on a different queue, exactly like the Just() publisher does.

Atalante answered 12/11, 2019 at 8:31 Comment(1)
your code works as expected in playgroundsKanpur
P
12

In my test of your code I'm getting false. Actually DispatchQueue has no one-to-one relation with some specific thread, it is a queue of execution and specifying DispatchQueue.global() you ask system to select some free queue to execute your task with default priority. So it is up to system to decide on which queue and in which thread to execute your task.

If you intentionally want to force it into background, then use

.subscribe(on: DispatchQueue.global(qos: .background))
Photoflood answered 17/11, 2019 at 7:27 Comment(1)
Thanks, that was it. However, I find interesting that when I was using DispatchQueue.global() the code in my custom publisher seems to be always executed on the main thread, but when I used Just() it seems to be always executed in a background thread. Anyway, I'm using the correct queue now.Atalante
G
1

To run code on the different thread, I believe it can use .receive(on:) to make the publisher run on the different thread

customPublisher()
.receive(on: DispatchQueue.global())
.map { _ in
    print(Thread.isMainThread)
}
.sink(receiveCompletion: { _ in }, receiveValue: { value in
    // Do something with the value received
}).store(in: &disposables)
Grosberg answered 15/4, 2023 at 3:30 Comment(0)
S
-1

Try use Deferred

func customPublisher() -> AnyPublisher<Bool, Never> {
   Deferred {
      return Future<Bool, Never> { promise in
         promise(.success(true))
      }
   }.eraseToAnyPublisher()
}
Stylite answered 30/3, 2023 at 9:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.