Conforming a type that has immutable but non-sendable properties to `Sendable`

Hey,

I'm playing around with Swift Concurrency and I'm trying to understand some basics around Sendable types. I set Concurrency checking to "Complete", so I get a lot of warnings.

Here's my current situation:

I have a struct that I need to pass around different concurrency domains (in potentially large quantities). That struct can contain a lot of "metadata" that I don't really want to be copying all the time. Since that data is completely immutable, I figured it would make sense to create an internal reference type to store it. Not sure that's the most recommended way, but I couldn't think of something better or more convenient for usage.

However, conforming the struct (and its inner reference type) to Sendable produces a warning that I'm not sure how to properly get rid of.

I have this minimal example here to keep it simple:

struct MyStruct: Sendable {
    final class Buffer: Sendable {
        let color: Color
        init(color: Color) {
            self.color = color
        }
    }

    private let buffer: Buffer

    var color: Color {
        buffer.color
    }

    init(color: Color) {
        buffer = Buffer(color: color)
    }
}

The color property inside Buffer produces the warning:

Warning: Stored property 'color' of 'Sendable'-conforming class 'Buffer' has non-sendable type 'Color'

I picked SwiftUI's Color type as an example of a non-sendable type. What would be the best thing to do here? color is a let, so it cannot be changed. Is it therefore safe to simply mark Buffer as @unchecked Sendable? That gets rid of the warning, but does it get actually rid of the problem (if there actually is one?)

I also tried turning Buffer into an actor, which also solved the warning. However, it produced two new warnings inside the struct itself:

[Inside the struct's color property] Non-sendable type 'Color' in asynchronous access to actor-isolated property 'color' cannot cross actor boundary

[Inside the struct's initializer] Non-sendable type 'Color' passed in call to nonisolated initializer 'init(color:)' cannot cross actor boundary

Maybe my entire approach is wrong? Is it bad to pass in a non-sendable type into a sendable type in the first place?

Thanks for any input on this :slight_smile:

1 Like

Late to the game, but in this case I think it would be best to use

@preconcurrency import SwiftUI