As far as I can tell AsyncPublisher and AsyncThrowingPublisher are not Sendable. I'm trying to address the Sendable warnings in our code when compiling with strict-concurrency.
The aforementioned types do not seem to be Sendable, but it seems to me they will be often used in context's that require them to be Sendable.
For example, I'm capturing a reference to an AsyncPublisher in a Task closure, and that closure requires the captures to be Sendable.
I got the same issue here. Passing an AsyncPublisher, which is commonly produced by .values of @Published array, into a function that iterates the values within a task triggers the warning of non-sendable type.
I don't know if there is an elegant solution to this common situation.
Hi! What will @preconcurrency tag do? It probably will suppress warnings, but will it make the code safe? As I understand, Sendable requires object to be actor-safe.
So if I have a class like this:
@preconcurrency import Combine
final class MyClass: Sendable {
static let shared = MyClass()
let publisher: AnyPublisher
}
Will it crash my app or not? When I access it from different context.
Yes @preconcurrency is a workaround to disable sendability checking for entire frameworks.
We are using publisher.values (which creates an AsyncSequence) quite a bit, but after checking, I noticed that we never pass this across isolation boundaries. I don't see AsyncThrowingPublisher conforming to Sendable in the docs, so that probably wouldn't work either.
There are certainly workarounds for your situation, but it depends on the constraints and requirements you have.
My easiest workaround would be prefixing MyClass with @MainActor, however, it's much more interesting to implement Sendable so shared instance would not produce any warning and the class would be usable from different contexts.
One approach would be to to abstract away the Publisher by wrapping it in an AsyncSequence. Plenty of approaches exist, depending on the requirements. E.g. if there's only ever one subscriber, then an AsyncStream suffices, and it offers buffering for free. For situations with multiple subscribers, we have MutableSharedStream in our codebase, which I'm unfortunately not at liberty to share.
Or, with some plumbing, you could make Shared from swift-sharing [1] work (adjustments needed if you want to mutate synchronously anywhere), which retains the current value. The idea is to start a Task that writes into Shared (or MutableSharedStream), and manage the Task's lifetime accordingly.
Seems irrelevant. You misconcept the idea of Combine mixing it with AsyncStream.
You think probably I need Combine because I want some data to be delivered asynchronously? It doesn't follows from my example. No, I want Combine because I want its features, including multiple subscribers and all that transformations.
Looks like you correctly understood that I'm speaking about Concurrency problems caused by shared. All static let properties required to be Sendable. And to make it Sendable we need all stored properties to be Sendable, including the publisher.
Using third party lib for a singleton seems to be a completely overkill for me.
Sorry man, initially you was very helpfull but the last post value dropped. Did you write it with LLM? If so, don't waist your time, I also use LLM, many of them.
AsyncSequence in principle supports "all that transformations", and multiple subscribers needs some workarounds that I've described. My posts are not LLM generated FWIW, but I feel you don't appreciate my answers so - hope you find a solution that suits you.