THE RIGHT WAY TO WRITE A SINGLETON
July 17, 2015
by Hector Matos
by Hector Matos
Even though I've written about the woes of managing state in my previous
post, sometimes there's just no way we can avoid it. One example of managing
state is something we're all quite acquainted with - The Singleton. The problem
we find in Swift is that there are SEVERAL ways of implementing them. But which
way is the right way? In this post I'm going to show you the history of the
singleton and then show you the right way to implement the singleton in Swift.

If you want to see the right way to implement the singleton pattern in
Swift along with proof of it's "right-ness", you can scroll to the
bottom of the post and see it there. :)
A TRIP DOWN MEMORY LANE
Swift is a natural evolution of Objective-C. In
Objective-C, this is how we implemented the singleton:
@interface Kraken : NSObject
@end
@implementation Kraken
+ (instancetype)sharedInstance {
static Kraken *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[Kraken alloc] init];
});
return sharedInstance;
}
@end
Now that we have that out of the way and we can see
the basic structure of a singleton, let's lay out some rules so we understand
what we're looking at:
DA RULES OF DA SINGLETON,
MAHN
There are essentially three things to remember
about the Singleton:
·
A singleton has to be unique. This is why it's called
a singleton. There can only be one instance for the lifetime
of the application it exists in. Singletons exist to give us singular global
state. Such examples are NSNotificationCenter, UIApplication, and NSUserDefaults.
·
To maintain a singleton's unique-ness, the initializer of a
singleton needs to be private. This helps to prevent other objects from
creating instances of your singeton class themselves. Thank you to all who
pointed that out to me :)
·
Because of rule #1, in order to have only one instance throughout the
lifetime of the application, that means it needs to be thread-safe.
Concurrency really sucks when you think about it, but simply put, if a
singleton is built incorrectly in code, you can have two threads try to
initialize a singleton at the same time which can potentially give you two
separate instances of a singleton. This means that it's possible for it to not
be unique unless we make it thread-safe. This means we want
to wrap the initialization in a dispatch_once GCD block to make sure the
initialization code only runs once at runtime.
Being unique and initializing in one place in an
app is easy. The important thing to remember for the rest of this post is that
a singleton fulfill the much-harder-to-see dispatch_once rule.
DA SWIFT SINGLETON
Since Swift 1.0, there have been several ways to
create a singleton. These have been covered very extensively here, here, and here.
But who likes clicking on links? SPOILER ALERT; There are four variations.
Allow me to count the ways:
THE UGLIEST WAY (A.K.A. THE "WHY ARE YOU STILL
CODING IN SWIFT IF YOU'RE JUST GOING TO DO THIS" WAY)
class TheOneAndOnlyKraken {
class var sharedInstance: TheOneAndOnlyKraken {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: TheOneAndOnlyKraken? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = TheOneAndOnlyKraken()
}
return Static.instance!
}
}
This way is a straight port of
Objective-C's singleton implementation over to Swift. Ugly in my opinion
because Swift was meant to be terse and expressive. Be better than the port
guys. Be better. :P

THE STRUCT
WAY (A.K.A. THE "OLD BUT STRANGELY STILL POPULAR" WAY)
class TheOneAndOnlyKraken {
class var sharedInstance: TheOneAndOnlyKraken {
struct Static {
static let instance = TheOneAndOnlyKraken()
}
return Static.instance
}
}
This way was how we had to do it in Swift 1.0 since
classes still didn't support static class variables back then. Structs,
however, did support them! Because of these restrictions on static variables,
we were forced into a model that looked like this. It's better than the
straight Objective-C port but still not good enough. Funnily enough, I still
see this method of writing singletons several months after the release of Swift
1.2. But more on that later.
THE GLOBAL VARIABLE WAY (A.K.A. THE SO CALLED
"ONE LINE SINGLETON")
private let sharedKraken = TheOneAndOnlyKraken()
class TheOneAndOnlyKraken {
class var sharedInstance: TheOneAndOnlyKraken {
return sharedKraken
}
}
As of Swift 1.2, we gained access
control specifiers and the ability to have static class
members. This meant that we didn't have to have a global variable
clutter the global namespace and we could now prevent namespace collisions.
This version is a lot Swiftier in my opinion.
Now at this point, you may be asking
why we don't see dispatch_once in our struct or global variable implementations. Well according to
Apple, both of these methods fulfills the dispatch_once clause I
outlined above. Here's a quote straight from their Swift
Blog that proves that they are wrapped in dispatch_once blocks
behind the scenes:
“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.”
— Apple's Swift Blog
That's all Apple gave us as far as official documentation goes. But this
meant that all we had proof for was global variables
and static members of structs/enums! At that point, the only 100% safe bet
backed by Apple docs was using a global variable to lazily wrap singleton initialization
in a dispatch_once block. BUT WHAT ABOUT OUR STATIC CLASS VARIABLES?!?!?!?
This very question brings us to this next exciting
section:
THE RIGHT WAY A.K.A. "THE ONE LINE SINGLETON
(NOW WITH PROOF!")
class TheOneAndOnlyKraken {
static let sharedInstance = TheOneAndOnlyKraken()
}

So I've done a fair amount of research for this post. In fact, this post
was inspired by a conversation we had at Capital One today due to the review of
a PR that aimed at achieving proper singleton consistency in Swift across our
app. We knew about this "right" method of writing singletons, but we
had no proof to back up our reasoning other than postulation. Trying to back
this method up without sufficient documentation was useless. It was my word
against a lack of information on the internet/blogosphere. And everyone knows
that if it isn't on the Internet it isn't true. This made me sad.

I navigated to the far ends of the internets (AKA the 10th page of Google
Search Results) and came up empty handed. Had no one posted proof of the one
line singleton yet?! Maybe they have, but it was hard to find.
So I decided to do something about it and wrote up
every way of initializing a singleton and inspected them at runtime using
breakpoints. After analyzing each stack trace for any similarities I came
across something interesting - PROOF!
Check it out, yo (Oh, and yay for
class emojis!):

Using the Global Singleton

Using the One Line Singleton
The first image shows the stack trace of a global let instantiation.
Outlined in red is the thing of interest here. Before the actual initialization
of the Kraken singleton is a call trace labeled swift_once followed
by a swift_once_block_invoke call. Since Apple said they lazily
instantiate global variables in a dispatch_once block, we can safely assume
this is what they meant.
Using this knowledge, I inspected the stack trace
of our shiny & pretty one-line-singleton. As you can see with our second
image, it's exactly the same! So there you have it! Proof that our one line
singleton is proper. All is now right with the world. Also, now that this post
is on the Internet, that MUST mean it's true!
wink wink
DON'T FORGET THE PRIVATE
INIT!
As @davedelong, Frameworks Evangelist at Apple,
graciously pointed out to me, you have to make sure that your inits are private.
This makes sure your singletons are truly unique and prevents outside objects
from creating their own instances of your class through virtue of access
control. Since all objects come with a default public initializer in Swift, you
need to override your init and make it private. This isn't too hard to do and
still ensures our one line singleton is nice and pretty:
class TheOneAndOnlyKraken {
static let sharedInstance = TheOneAndOnlyKraken()
private init() {} //This prevents others from using the default '()'
initializer for this class.
}
Doing this will makes sure that
the compiler throws this error when any class attempts to initialize TheOneAndOnlyKraken using
the () initializer:
And there you have it! The perfect, one-line singleton.
CONCLUSION
Echoing jtbandes' excellent
comment on the top rated answer to swift singletons on Stack Overflow,
I simply could not find documentation anywhere that proved thread-safety by
"virtue of let". I actually remember something of the sort said when
I was at WWDC last year, but you can't expect readers or quick Googlers to
stumble across that when trying to make sure this is the right way to write a
singleton in Swift. Hopefully, this post can help someone out there understand
why the one-line singleton in Swift is the way to go.
Happy coding fellow nerds!

17 Comments 54 Likes
Share
tagged with dispatch_once swift, swift singleton, dispatch_once, singleton in swift, swift, virtue of let
Megjegyzések
Megjegyzés küldése