I want to have a thread safe, ARC compatible singleton, but is seems to me that the most common example of singleton that I find, an example pasted here:
+ (MyClass *)sharedInstance
{
static MyClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
// Do any other initialisation stuff here
});
return sharedInstance;
}
doesn't stops other developer from calling [[MyClass alloc] init] and overriding the desired flow. What is the proper way to handle it (apart from throwing exception in init)?
I tend to use the following: (with newer
instancetype
compiler syntax)This also doesn't prevent others from calling
[[MyClass alloc] privateInit]
but it will warn them (unless they write their own hushing code).This would also leak pre-ARC if someone calls
[[MyClass alloc] init]
- but you've got bigger problems if that happens. Optionally, you could throw an exception when init is called. (as in holex's answer)Also, subclasses could theoretically get in a race condition. If you're worried about that change
@synchronized (self)
to@synchronized ([McClass class])
. I prefer theself
as cleaner code and I know there won't be subclasses.convert instance to class method and use the Class object as the singleton.
for example you have a singleton class like this
I am suggesting you to convert it to
in MySingleton.m
then you can use it like
or
EDIT
I just want to point out, there are already so many ObjC implementation for singleton pattern.
http://www.cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html https://github.com/fadingred/objc-singleton
simple google search will find them. everything are considered. (much more than what I was expected)
you also have to override the
+alloc
method to avoid to allocate more than one instance of the singleton.EDIT#3: well, I really know what the official documentation says about overriding the
+alloc
method, but to achieve the asked benefit there is no way to avoid it. personally I don't agree to do it but it can provide the desired result.it would be like this:
EDIT #1
you don't definitely need to throw an exception here but it is much more visual feedback for the developers of they use your class in wrong way, than sending back a simple
nil
pointer.EDIT #2
I've added a simple trick to avoid the developers instantiate the class to bypass the modified
+alloc
method, in that case the allocation will work well but the-init
will throw an exception.Use the Borg pattern instead of the Singleton pattern: Allow multiple instantiation of your class and have the instances share the same static state.
This way, clients may arbitrarily use static
getInstance
methods orinit
methods, and receive objects sharing the same state. They need not even be aware that it's a singleton.