Sendability for Stream, InputStream, etc.

I have a project with some legacy networking code that uses the Stream (formerly NSStream) family of classes, including Stream, InputStream, OutputStream, and StreamDelegate.

None of these are sendable, so I get a lot of warnings when implementing delegate methods in a @MainActor class.

These classes seem like they could be sendable. Is this something that will happen soon? Is it a bug I should report?

The networking code that uses these classes runs great, and hasn't needed changes for years, so my current solution is to just mark these unchecked:

extension Stream: @unchecked Sendable { }
extension InputStream: @unchecked Sendable { }
extension OutputStream: @unchecked Sendable { }

This makes the compiler happy, but makes me feel kind of bad. Is there something else I could do?

These classes seem like they be sendable. Is this something that will happen soon?

Obviously I can’t predict the future, but I doubt it. The Foundation stream APIs are no longer mainstream, so I’d be surprised if we put a lot of effort into their concurrency model.

This case is particularly problematic because of the way thread safety works with these types. There are two ways you can use them asynchronously:

  • With a run loop

  • With a Dispatch queue

Run loops are tricky in Swift concurrency because the Swift concurrency model breaks the connection between the thread and the execution context. The only reliable way to schedule a run loop source is on the current run loop, but that’s tied to the current thread, which is meaningless in a Swift async function.

If you really needed to continue using the stream APIs — for example, in this thread I’m talking to someone using the External Accessory framework, where there’s no alternative — then it’d make sense to apply some heroic effort here. For example, you could:

  • Do this work in an actor.

  • Install a Dispatch queue as the custom executor for that actor.

  • Schedule your streams on that queue.

However, in this case I’m reluctant to suggest that because, if you’re going to do that much work, it’d make more sense moving off the deprecated CFSocketStream and on to NWConnection.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Sendability for Stream, InputStream, etc.
 
 
Q