I'm trying to work out an appropriate singleton model for usage in Swift. So far, I've been able to get a non-thread safe model working as:
class var sharedInstance: TPScopeManager { get { struct Static { static var instance: TPScopeManager? = nil } if !Static.instance { Static.instance = TPScopeManager() } return Static.instance! } }
Wrapping the singleton instance in the Static struct should allow a single instance that doesn't collide with singleton instances without complex naming schemings, and it should make things fairly private. Obviously though, this model isn't thread-safe. So I tried to add dispatch_once
to the whole thing:
class var sharedInstance: TPScopeManager { get { struct Static { static var instance: TPScopeManager? = nil static var token: dispatch_once_t = 0 } dispatch_once(Static.token) { Static.instance = TPScopeManager() } return Static.instance! } }
But I get a compiler error on the dispatch_once
line:
Cannot convert the expression's type 'Void' to type '()'
I've tried several different variants of the syntax, but they all seem to have the same results:
dispatch_once(Static.token, { Static.instance = TPScopeManager() })
What is the proper usage of dispatch_once
using Swift? I initially thought the problem was with the block due to the ()
in the error message, but the more I look at it, the more I think it may be a matter of getting the dispatch_once_t
correctly defined.
In Swift, Singleton is a design pattern that ensures a class can have only one object. Such a class is called singleton class. An initializer allows us to instantiate an object of a class. And, making the initializer of a class restricts the object creation of the class from outside of the class.
You can create a thread safe singleton using DispatchQueue. We will create a serial queue and add a sync method to set and get value. Below is the code you can achieve thread safe singleton class. It will write an another blog where we can improve the performance using dispatch barrier.
A programmer cannot inherit the pure-singleton class. When you try to inherit any class in swift, you must call the constructor of the superclass.
AppDelegate is however a singleton class but you show only use it for declaring things that applies globally in your application. For ex: If you want to change the color of navigation bar in your entire application you can use app delegate and set the color of navigation bar.
tl;dr: Use the class constant approach if you are using Swift 1.2 or above and the nested struct approach if you need to support earlier versions.
From my experience with Swift there are three approaches to implement the Singleton pattern that support lazy initialization and thread safety.
class Singleton { static let sharedInstance = Singleton() }
This approach supports lazy initialization because Swift lazily initializes class constants (and variables), and is thread safe by the definition of let
. This is now officially recommended way to instantiate a singleton.
Class constants were introduced in Swift 1.2. If you need to support an earlier version of Swift, use the nested struct approach below or a global constant.
class Singleton { class var sharedInstance: Singleton { struct Static { static let instance: Singleton = Singleton() } return Static.instance } }
Here we are using the static constant of a nested struct as a class constant. This is a workaround for the lack of static class constants in Swift 1.1 and earlier, and still works as a workaround for the lack of static constants and variables in functions.
The traditional Objective-C approach ported to Swift. I'm fairly certain there's no advantage over the nested struct approach but I'm putting it here anyway as I find the differences in syntax interesting.
class Singleton { class var sharedInstance: Singleton { struct Static { static var onceToken: dispatch_once_t = 0 static var instance: Singleton? = nil } dispatch_once(&Static.onceToken) { Static.instance = Singleton() } return Static.instance! } }
See this GitHub project for unit tests.
Since Apple has now clarified that static struct variables are initialized both lazy and wrapped in dispatch_once
(see the note at the end of the post), I think my final solution is going to be:
class WithSingleton { class var sharedInstance: WithSingleton { struct Singleton { static let instance = WithSingleton() } return Singleton.instance } }
This takes advantage of the automatic lazy, thread-safe initialization of static struct elements, safely hides the actual implementation from the consumer, keeps everything compactly compartmentalized for legibility, and eliminates a visible global variable.
Apple has clarified that lazy initializer are thread-safe, so there's no need for dispatch_once
or similar protections
The lazy initializer for a global variable (also for static members of structs and enums) is run the first time that global is accessed, and is launched as dispatch_once to make sure that the initialization is atomic. This enables a cool way to use dispatch_once in your code: just declare a global variable with an initializer and mark it private.
From here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With