It feels like the state of the art for creating singletons changes every year. The (somewhat) new hotness is to use dispatch_once to create them:

+ (instancetype) sharedInstance
{
    static dispatch_once_t onceToken;
    static id sharedInstance;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

(I use instancetype (read more) here but please don’t ever subclass singletons. It won’t end well.)

This works great: dispatch_once is fast, mostly because it doesn’t require any locks. GCD handles all of the heavy lifting.

The problem arises if you ever want to assert that there is only ever one instance of this singleton. If you use this code, it will provide a shared instance of the class that is globally accessible, but any other consumer of the code will be able [[Singleton alloc] init] their way into a new instance, which could be problematic, depending on how you want your code to be used.

Usually, the check to make sure that no other instances are created is handled in +alloc and to make sure that it is thread-safe, it is wrapped in an @synchronized block.

static typeof(self) _sharedInstance = nil;
 
+ (instancetype)sharedInstance
{
    @synchronized(self){
        if (!_sharedInstance) {
            _sharedInstance = [[self alloc] init];
        }
        return _sharedInstance;
    }
    return nil;
}
 
+ (id)alloc
{
    @synchronized(self){
        NSAssert(_sharedInstance == nil, @"Attempt to allocate a second instance of singleton %@", [self class]);
        _sharedInstance = [super alloc];
        return _sharedInstance;
    }
    return nil; 
}

We don’t want to use @synchronized however, since we’re moving away from locks and towards queues. What we need a way to be able to alloc ourselves, without allowing external classes to alloc.

The solution I came up with for this is to called [super allocWithZone:nil] in our accessor, and overriding +allocWithZone: in the singleton to raise an exception.

+ (instancetype) sharedInstance
{
    static dispatch_once_t once;
    static id sharedInstance;
    dispatch_once(&once, ^{
        sharedInstance = [[super allocWithZone:nil] init];
    });
    return sharedInstance;
}
 
+ (id) allocWithZone:(NSZone *)zone {
    NSString *reason = [NSString stringWithFormat:@"Attempt to allocate a second instance of the singleton %@", [self class]];
    NSException *exception = [NSException exceptionWithName:@"Multiple singletons"
                                            reason:reason
                                          userInfo:nil];
    [exception raise];
 
    return nil;
}

This way, anyone trying to access from the outside will call +alloc, which will call +allocWithZone, which will crash the app. My understanding is also that zones are basically deprecated, and every app only has one zone anyway, making it okay to pass nil in for that parameter.

If there’s a better solution for this, I’d love to hear about it. @khanlou or soroush@khanlou.com

Update: Alejandro Ramirez ((@j4n0) wrote in to share a different way to handle the same thing: adding compiler errors for when init, copy, and new are called. In your header file:

+(instancetype) sharedInstance;
 
// clue for improper use (produces compile time error)
+(instancetype) alloc __attribute__((unavailable("alloc not available, call sharedInstance instead")));
-(instancetype) init  __attribute__((unavailable("init not available, call sharedInstance instead")));
+(instancetype) new   __attribute__((unavailable("new not available, call sharedInstance instead")));

You can find all the code on his gist.