Using Combine/readPublisher

Am I doing this right? I have a few Player in the db but I see just

players2: Combine.AnyCancellable

twice in the log. How do I receive these values asynchronously?

        let players = AppDatabase.shared.databaseReader.readPublisher(
            receiveOn: DispatchQueue.global(),
            value:
                { db in
                    try Player.fetchAll(db)
                }
        )
            .sink { item in
                print("item: \(item)")
            } receiveValue: { players in
                print("players1: \(players)")
            }

        print("players2: \(players)")

log:

players2: Combine.AnyCancellable
players2: Combine.AnyCancellable

If I remove the .sink {} I see:

players2: Read<Array<Player>>(upstream: AnyPublisher)
players2: Read<Array<Player>>(upstream: AnyPublisher)

I know I'm close but I'm obviously doing this wrong ..

Combine is a set of APIs on how to build recipes for describing asynchronous work, not the values of said work. That means that your publisher is the description of how the work is done, not the results. The sink operation is a way of saying: hey request an unlimited amount of values to kick of the work described and funnel values to this thing until it hits termination or the cancellation token (the AnyCancellable) is either deallocated or explicitly cancelled.

In short; it is better to avoid trying to make such an asynchronous thing synchronous; it will just lead to problems.

The issue that you are likely encountering here is that once that AnyCancellable drops out of scope it cancels the work that would be done - that thing needs to be kept around until you have no more need of values being emitted from it.

2 Likes

Thank you @Philippe_Hausler :slight_smile:

Indeed @mazz, if you want players, you can just fetch them right away:

let players = try AppDatabase.shared.databaseReader.read { db in
    try Player.fetchAll(db)
}
print(players) // Some actual players (if the db is not empty)

Thanks, yes I just needed to have a Cancellable instance and it works great now.

1 Like

Hi @gwendal.roue so I've been using the synchronous .read up until now and it works great but starting on a new epic in the app's development and I'd like to start fetching things asynchronously as I've noticed when fetching large amounts of data that it is blocking UI presentation.