Actor and the Singleton Pattern

As I migrate my apps to Swift 6 one by one, I am gaining a deeper understanding of concurrency. In the process, I am quite satisfied to see the performance benefits of parallel programming being integrated into my apps.

At the same time, I have come to think that actor is a great type for addressing the 'data race' issues that can arise when using the 'singleton' pattern with class.

Specifically, by using actor, you no longer need to write code like private let lock = DispatchQueue(label: "com.singleton.lock") to prevent data races that you would normally have to deal with when creating a singleton with a class. It reduces the risk of developer mistakes.


import EventKit

actor EKDataStore: Sendable {
    
    static let shared = EKDataStore()
    
    let eventStore: EKEventStore
    
    private init() {
        self.eventStore = EKEventStore()
    }
}

Of course, since a singleton is an object used globally, it can become harder to manage dependencies over time. There's also the downside of not being able to inject dependencies, which makes testing more difficult.

I still think the singleton pattern is ideal for objects that need to be maintained throughout the entire lifecycle of the app with only one instance. The EKDataStore example I gave is such an object.

I’d love to hear other iOS developers' opinions, and I would appreciate any advice on whether I might be missing something 🙏

Answered by DTS Engineer in 806576022

I see two trade-offs here:

  • Actors vs Dispatch queues

  • Singletons vs dependency injection

To my mind those are different things. You can mix’n’match them as you see fit. Specifically, there’s no need to give up on dependency injection because you switched from a Dispatch queue to an actor. You just have to inject an instance of the actor rather than an instance of your previous class that wrapped the Dispatch queue.

Share and Enjoy

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

Accepted Answer

I see two trade-offs here:

  • Actors vs Dispatch queues

  • Singletons vs dependency injection

To my mind those are different things. You can mix’n’match them as you see fit. Specifically, there’s no need to give up on dependency injection because you switched from a Dispatch queue to an actor. You just have to inject an instance of the actor rather than an instance of your previous class that wrapped the Dispatch queue.

Share and Enjoy

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

Actor and the Singleton Pattern
 
 
Q