Use Class Methods for Cocoa Singletons

Here’s a common pattern I see all the time in Cocoa development involving Singletons (let’s put aside any judgement as to whether or not the Singleton pattern is a good one and just roll with this for a moment): the singleton class Thing exposes a class method called +sharedThing which returns a shared instance of the class, and then has a bunch of instance methods to do real work. Here’s what the interface might look like:

@interface Thing : NSObject

+ (instancetype)sharedThing;
- (void)doYourStuff;
- (void)setGlobalToggleEnabled:(BOOL)enabled;

@end

It’s all your standard fare. When your client wishes to use it, you end up with the rather silly looking:

[[Thing sharedThing] doYourStuff];
[[Thing sharedThing] setGlobalToggleEnabled:YES];

Every time I want to do something with the singleton, I’ve got to first request it from the class, then I send that instance a message. It’s straightforward enough, but it gets tedious real quick, and it begins to feel like a part of the implementation is leaking out.

When I use a singleton class, I shouldn’t really have to care about the actual instance. That’s an implementation detail and I should just treat the whole class as a monolithic object. I’m sending a message to the House itself, I don’t care what houseling lives inside.

So instead, I’d recommend hiding the sharedWhatever away from clients of your API. You can still just as easily have a shared, static instance of your class, but there’s no need for that to be public. Instead, give your class’s consumers class methods to work with:

@interface Thing : NSObject

+ (void)doYourStuff;
+ (void)setGlobalToggleEnabled:(BOOL)enabled;

@end

@implementation Thing

+ (instancetype)sharedThing { /* return it as usual */ }

+ (void)doYourStuff {
    Thing *thing = [self sharedThing];
    thing.privatePropertyCount += 1;
}
// etc.

If your singleton class needs to store some state (and please try really hard to avoid storing global state), you can still use private properties (via the Class Extension) and expose necessary ones as class methods, too. Exposing global state this way is a bit more work, but doing this work is kind of a natural immune response of the language to discourage you from doing so, anyway.

Sometimes singletons are a necessary evil, but that doesn’t mean they necessarily have to be unpleasant. Hiding away the implementation detail of a “shared instance” frees other programmers from having to know about the internals of your class, and it prevents them from doing repetitive, unnecessary typing.

Let’s class up our singletons.

Join the Discussion 👂🤔✍️

Please read the Discussion Guidelines before replying.

☑️ Email me when someone replies.

Speed of Light