Home > Enterprise >  Can a class be Sendable if it holds a reference to a non-Sendable singleton?
Can a class be Sendable if it holds a reference to a non-Sendable singleton?

Time:12-08

Suppose I have a class whose only state is a reference to a singleton class:

class MyClass {
    let networkHelper: NetworkHelper

    func makeNetworkRequest(_ url: URL) {
        networkHelper.actuallyMakeNetworkRequest(url)
    }
}

The NetworkHelper class is not Sendable; it maintains some mutable state (although that state is mostly invisible to outside callers). However, the class is a singleton and so any two instances of MyClass will always hold references to the same NetworkHelper.

Given that MyClass contains no mutable state of its own, and that it does hold a reference to a non-Sendable class instance, does MyClass conform to Sendable?

CodePudding user response:

From documentaion

Sendable Classes To satisfy the requirements of the Sendable protocol, a class must:

Be marked final

Contain only stored properties that are immutable and sendable

Have no superclass or have NSObject as the superclass

Classes marked with @MainActor are implicitly sendable, because the main actor coordinates all access to its state. These classes can have stored properties that are mutable and nonsendable.

Classes that don’t meet the requirements above can be marked as @unchecked Sendable, disabling compile-time correctness checks, after you manually verify that they satisfy the Sendable protocol’s semantic requirements.

According to this, to be sendable

  • Your MyClass should be final
  • Your singleton, networkHelper should be immutable and sendable
  • Should have no superclasses [Which already is]

CodePudding user response:

In short, because NetworkHelper is not Sendable, MyClass cannot be Sendable either. The fact that NetworkHelper is a singleton is immaterial.

FWIW, the compiler will help you out here: If you attempt to make MyClass conform to Sendable (by making it final and adding Sendable conformance), the compiler will tell you about the issue with NetworkHelper not being Sendable:

final class MyClass: Sendable {
    let networkHelper: NetworkHelper = .shared    // Stored property 'networkHelper' of 'Sendable'-conforming class 'MyClass' has non-sendable type 'NetworkHelper'

    func makeNetworkRequest(_ url: URL) {
        networkHelper.actuallyMakeNetworkRequest(url)
    }
}

enter image description here

For MyClass to be Sendable, you will need to make NetworkHelper conform to Sendable, too.

FWIW, if NetworkHelper has a mutable state, you probably want to make it threadsafe, anyway, and once you do that, making it Sendable, too, is easy.

  • Related