The Singleton conundrum

Everywhere I go I find Singletons in the code base. It doesn't seem to matter what language or system, developers keep putting them in. Sometimes these singletons make sense. Some times they don't. Running a Singleton for accessing data from a server makes sense when the server can only handle one request at a time. A Singleton for managing a file makes sense when to want to ensure that the app cannot both read and write at the same time. Apple's iOS APIs use the Singleton pattern quite often. Anyone who has used NSUserDefaults or executed [UIApplication sharedApplication] has used them.

But a lot of the time I find Singletons where they really don't need to be and often their presence actually makes some development tasks harder. The problem (I suspect) is that some developers use Singletons as an "easy" way to access something. Singletons make this easy because you don't have to pass a reference to an object around between classes or locate it in some other way.

The other BIG problem with singletons appears when testing. Because of the nature of the Singlton pattern it's often difficult or near impossible to mock it for testing purposes. Here's an example of a typical Singleton access method in Objective C (code from Singletons in Objective C - Matt Galloway):

+ (id)sharedManager {
    static MyManager *sharedMyManager = nil;
    @synchronized(self) {
        if (sharedMyManager == nil)
            sharedMyManager = [[self alloc] init];
    }
    return sharedMyManager;
}

As you can see any time you use [MyManager sharedManager] you will get the same instance. Simple and dead easy to use from anywhere in your code.

In case you haven't noticed there is actually a problem with this code. Whilst it creates a single instance of the class, it's only a true Singleton if you use the sharedMyManager method to get to it. There is actually nothing to stop me creating another instance of this class outside this code.

It is possible to create a pure Singleton in Objective C and Matt's older non-ARC Singleton code did that. I would not recommend this approach as it's even harder to work with.

Testing Singletons

There is a problem when testing (Sorry Matt - I know you like them!) Singletons. I often want to mock out MyManager so I can predefine responses and/or check that it is called from the code I'm testing. So I might want to do this:

... // inside a unit test
id mockManager = [OCMockObject mockForClass:[MyManager class];
// ... hmmm now how do I get my code to use it?

BTW, if you don't already use it, go checkout OCMock, it's a really solid mocking framework for your unit tests.

The problem here is that the Singleton instance is protected by the method that access it. I cannot set it.

I can actually get around this using OCMock, but it takes a bit of engineering to do so and thanks to recent changes in the iOS runtime, it's not as reliable as it used to be. The way to deal with this is to stub out the sharedMyManager getter itself. So the protected Singleton is never accessed. Not as nice as injecting a mock, but it works. Check out the Class methods section in the OCMock doco for how to do this.

A slightly less strict pattern - The Temporal Singleton

What I would rather do is have a singleton pattern which is not as strict as the pure Singleton pattern would like. I would like it to allow only one to exist at any time, but still allow me to replace the one that exists. So I cannot create multiple instances, but I can change the one that's there.

The advantage of this is that it allows me to swap in a different implementation at my leasure. But not (at any time) have more than one running. I'm still working on this concept.


Comments powered by Disqus