Wednesday, July 9, 2014

Singleton

The Singleton model is often used to instantiate just one instance of a class which doesn’t allow a second instance of that same class to be loaded anywhere in the application. Some implementations will throw an exception if you try to create a second instance of the class, some will create the singleton for you when you first try to access it, and some will even let you create other instances if you want, but will always manage a ‘single shared instance’ for you. Many of the core Apple classes follow this pattern, such as [UIApplication sharedApplication].
Anyway, Apple do a very good job (naturally) of providing a good example of the Singleton model. The following code is rather similar to the Apple example, but it also includes what you should have in the header file. It is also a stable part of any library of code snippets, so it has to be here really!
SingletonClass.h
?
1
2
3
4
5
6
7
8
#import <Foundation/Foundation.h>
 
@interface SingletonClass : NSObject {
 
}
 
+ (id)sharedInstance;
@end
SingletonClass.m
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#import "SingletonClass.h"
 
@implementation SingletonClass
 
static SingletonClass *sharedInstance = nil;
 
// Get the shared instance and create it if necessary.
+ (SingletonClass *)sharedInstance {
    if (sharedInstance == nil) {
        sharedInstance = [[super allocWithZone:NULL] init];
    }
 
    return sharedInstance;
}
 
// We can still have a regular init method, that will get called the first time the Singleton is used.
- (id)init
{
    self = [super init];
 
    if (self) {
        // Work your initialising magic here as you normally would
    }
 
    return self;
}
 
// Your dealloc method will never be called, as the singleton survives for the duration of your app.
// However, I like to include it so I know what memory I'm using (and incase, one day, I convert away from Singleton).
-(void)dealloc
{
    // I'm never called!
    [super dealloc];
}
 
// We don't want to allocate a new instance, so return the current one.
+ (id)allocWithZone:(NSZone*)zone {
    return [[self sharedInstance] retain];
}
 
// Equally, we don't want to generate multiple copies of the singleton.
- (id)copyWithZone:(NSZone *)zone {
    return self;
}
 
// Once again - do nothing, as we don't have a retain counter for this object.
- (id)retain {
    return self;
}
 
// Replace the retain counter so we can never release this object.
- (NSUInteger)retainCount {
    return NSUIntegerMax;
}
 
// This function is empty, as we don't want to let the user release this object.
- (oneway void)release {
 
}
 
//Do nothing, other than return the shared instance - as this is expected from autorelease.
- (id)autorelease {
    return self;
}
 
@end
There you go – copy and paste this into your new project, rename the interface and implementations and you’re done – a ready to use Singleton in your project.
Making the creation of your singleton thread safe
Jiunn Harr wrote a great blog post on making the creation of your Singleton thread safe. In the above example, it is possible that your Singleton’s init method could be called more than once, if sharedInstance was called for the first and second time concurrently on different threads. In order to by-pass this problem, you can replace the sharedInstance method above with the following;
?
01
02
03
04
05
06
07
08
09
10
11
12
+ (SingletonClass *)sharedInstance {
    if (nil != sharedInstance) {
        return sharedInstance;
    }
 
    static dispatch_once_t pred;        // Lock
    dispatch_once(&pred, ^{             // This code is called at most once per app
        singleton = [[SingletonClass alloc] init];
    });
 
    return singleton;
}
Note. This doesn’t make all calls on your Singleton thread safe – it simply ensures that the creation of your Singleton is thread safe. This code uses Grand Central Dispatch (Cocoa and iOS4+). To read more about how this works, and why you should consider using it – check out Jiunn Haur’s great blog post on the subject.
Using the Singleton Class
The above code creates the framework for a Singleton class. You can almost ignore the majority of the code above and no go about setting up your own variables and methods for use in your singleton class. It’s worth bearing in mind that when you first attempt to you access your Singleton, it will be created for you, and from that point onwards – it will probably reside in memory for the remainder of your application’s lifecycle. Because of this, you might want to be careful about memory usage and ensure that classes inside your singleton element are tidy.
Accessing your Singleton class from your code is then simply a matter of using the +(SingletonClass*)sharedInstance to get a pointer to the one instance of the singleton class that exists in your application. You can do this anywhere in your code and you would do this for the above class by doing something like the following;
?
1
2
SingletonClass* sharedSingleton = [SingletonClass sharedInstance];
[sharedSingleton callAMethod];