Singleton Design Pattern

A singleton is an object class designed such that only one instance of that class will ever exist. This can be useful to minimize resources required (e.g., database connections) or ensure consistent data throughout an application (e.g., user preferences).

With the advent of automatic reference counting (ARC) in Objective-C, a lot of memory management has changed (for the better). The transition from manual reference counting to ARC is generally straightforward (there is even a refactoring tool in Xcode to speed the process), but some changes require a bit more work (and understanding). If you have implemented a singleton class, for example, you will see a number of errors in the ARC refactor preview.

Manual Reference Counting

I will begin with the manual reference counting approach. The general structure here is outlined in the Apple Documentation as well, but has not been updated (to the best of my knowledge) for ARC.

Listing: SomeFactory.h

@interface SomeFactory : NSObject

@property (nonatomic, retain) NSMutableArray * collection;

+ (SomeFactory *)defaultFactory;

@end

The theory here is to override any method that might result in the allocation of a new object of the singleton class. The normal memory management methods (retain, release, and retainCount) are overridden since there should always be a retain count of 1 for the Singleton object. The NSUIntegerMax value returned by the retainCount() method is designed to provide a hint that a singleton is being used.

Listing: SomeFactory.m

#import "SomeFactory.h"

static SomeFactory *defaultFactory = nil;

@implementation SomeFactory

@synthesize collection;

+ (LibraryFactory *)defaultFactory
{
    if (! defaultFactory)
    {
        defaultFactory = [[super allocWithZone:NULL] init];
    }
    return defaultFactory;
}

+ (id)allocWithZone:(NSZone *)zone
{
    return [self defaultFactory];
}

- (id)init
{
    if (defaultFactory) return defaultFactory;

    [super init];

    collection = [[NSMutableArray alloc] init];

    return self;
}

- (id)retain
{
    return self;
}

- (oneway void)release
{

}

- (NSUInteger)retainCount
{
    return NSUIntegerMax;
}

@end

In summary, you create a static instance and always return that static instance. If no instance yet exists, create it.

Automatic Reference Counting (ARC)

Under ARC, you neither implement nor call retain, release, autorelease, or retainCount. For autorelease, under some circumstances, you might create an @autoreleasepool structure. After removing forbidden methods, as well as making your singleton thread safe, you have the following.

Listing: SomeFactory.h

@interface SomeFactory : NSObject

@property (nonatomic, strong) NSMutableArray * collection;

+ (SomeFactory *)defaultFactory;

@end

Listing: SomeFactory.m

#import "SomeFactory.h"

static SomeFactory *defaultFactory = nil;

@implementation SomeFactory

@synthesize collection;

+ (SomeFactory *)defaultFactory
{
    @synchronized([SomeFactory class]) {
        if (! defaultFactory) {
            defaultFactory = [[SomeFactory alloc] init];
        }
    }
    return defaultFactory;
}

- (id)init
{
    if (self = [super init]) {
        collection = [[NSMutableArray alloc] init];
    }
    return self;
}

@end