How I do my singletons

This is something that comes up again and again.  How do you make a true singleton in Objective-C? I was just asked this the other night, so I decided to write up my version of an Objective-C singleton.

For starters, there’s an example in the documentation on how you could make a singleton. It’s a pretty bizarre implementation. StackOverflow.com has a nice long discussion on what people consider acceptable singletons. Peter Hosey wrote an in-depth post about it a while back as well, with a different example of what he considers a good singleton.

Go read those articles, then come back.

Have you read them yet? Good.

I think Peter’s overview of what makes a singleton is very good. In particular, he has several criteria that, if met, help define a singleton. They are:

  1. +sharedFramistan always returns the same object.
  2. +alloc/-init always produce the same object (which, itself, is the same object as +sharedFramistan).
  3. +alloc/-init will not return an object confused by multiple init messages.
  4. Over-releasing causes a crash.
  5. Keeping +alloc/+allocWithZone:/-retain balanced with release never causes a crash.
  6. If [super init] returns a different object, +alloc/-init won’t break.

Over the couple years, I’ve developed my own singleton pattern. I think it’s pretty simple, it gets the job done, and it’s fairly idiot-proof. It does have a drawback, which is that the singleton exists for the lifetime of the process; it is not lazily created. If that’s a problem for you, well then this singleton probably isn’t for you. Other than that, it has served me very well.

So, without further ado, here it is:

// DDFramistan.h
@interface DDFramistan : NSObject

+ (id) sharedFramistan;

@end

// DDFramistan.m

static DDFramistan *_sharedFramistan = nil;

__attribute__((constructor)) static void construct_singleton() {
  NSAutoreleasePool * p = [[NSAutoreleasePool alloc] init];
  _sharedFramistan = NSAllocateObject([DDFramistan class], 0, nil);
  [p drain];
}

__attribute__((destructor)) static void destroy_singleton() {
  NSAutoreleasePool * p = [[NSAutoreleasePool alloc] init];
  NSDeallocateObject(_sharedFramistan), _sharedFramistan = nil;
  [p drain];
}

@implementation DDFramistan

+ (id)sharedFramistan {
  return _sharedFramistan;
}

+ (id) allocWithZone:(NSZone *)zone {
  return [[DDFramistan sharedFramistan] retain];
}

@end

The only really weird things going on here are those two functions, construct_singleton() and destroy_singleton(). What’s up with those? Basically, by tacking that __attribute__((constructor)) onto the function declaration, this function will get invoked before execution enters main(). As such, we have to set up an NSAutoreleasePool for the off-chance that we happen to create any autoreleased objects during singleton creation. Also, I’m using the NSAllocateObject() function, which is pretty much the same thing as class_createInstance(). That’s going to allocate a new object for me on the heap, with all of the members of that object set to 0 (ie, it’s essentially using calloc()).

Similarly, the __attribute__((destructor)) function is one that will get executed after returning from main() (or exit()). This one isn’t quite as necessary, since if the program is exiting, all the memory is going to get cleaned up anyway. However, if you’ve got shared resources (file descriptors, etc), this would be the place to clean them up. Again, we wrap the deallocation in an NSAutoreleasePool to catch any autoreleased objects that may get created in the process (which would be weird, but not impossible).

As for the methods on the singleton itself, they’re really straight forward:

  • +sharedFramistan returns our singleton
  • +allocWithZone: returns the static singleton, retained (just like it’s supposed to)
  • Since we have no -init method, we’ll simply inherit the one belonging to NSObject. -[NSObject init] is documented to simply return self, so we’re safe to invoke it as many times as we want.

Other than that, it’s a perfectly normal Objective-C object. Let’s go over Peter’s list and see how we did:

  1. +sharedFramistan always returns the same object.
    Yep, we got that.

  2. +alloc/-init always produce the same object (which, itself, is the same object as +sharedFramistan).
    Yep, we got that too.

  3. +alloc/-init will not return an object confused by multiple init messages.
    Since the init method does do anything, this is easily accomplished.

  4. Over-releasing causes a crash.
    We’re not doing anything bizarre with memory management, so if you over-release the singleton, it will get deallocated prematurely, and accessing it after that will cause your program to crash. So… check.

  5. Keeping +alloc/+allocWithZone:/-retain balanced with release never causes a crash.
    Again, we’re good here. As long as you don’t over-release, this object will never go away.

  6. If [super init] returns a different object, +alloc/-init won’t break.
    Since we don’t implement -init, we don’t have to worry about this.

Looks pretty good!

Now, the moment we’ve all been waiting for…

Is DDFramistan a true singleton?

NO.

DDFramistan is not a true singleton. A true singleton would never allow another instance of the object to be created under any circumstances. Unfortunately, Objective-C has fun things like NSAllocateObject() and class_createInstance() that allow us to easily bypass all of the normal object creation business, and there’s nothing we can do about that (that I can think of). So while it’s unlikely that you would ever create another instance of DDFramistan, it’s not impossible. And therefore, this is not a true singleton.

But it’s probably good enough (and it’s about as close as you can get).


History

  • 24 Feb 2011 - Original post
  • 24 Feb 2011 - removed unnecessary init method, as suggested in the comments

  1. funwithobjc posted this
Short URL for this post: http://tmblr.co/Zt522y3FMzgG
blog comments powered by Disqus