The Singleton pattern

In chapter 4, we recommend using +initialize to create singletons. This used to be a good pattern, but it’s become dated since the addition of Grand Central Dispatch. It’s time to update our pattern to modern tools. Our new recommendation is the GCD way (replace id with your classname):

+ (id)sharedManager
{
  static id sharedManager;
  static dispatch_once_t once;
  dispatch_once(&once, ^{
    sharedManager = [[self alloc] init];
  });
  return sharedManager;
}

7 comments

  1. Robert Abramovitz

    I have a question concerning the singleton code examples. On page 73 in the initSingleton method [super init] is invoked twice. Is this intentional? If so, why?

    • This was a typo. I merged two different init methods. But we don’t recommend using that pattern at all anymore. The dispatch_once() pattern shown here is our new recommendation.

  2. Jake Krog

    On a side note, the class assertion in +initialize interferes with KVO.

    When you observe an object, a subclass prefixed with “NSKVONotifying_” is created automatically. If you register a KVO observer on a singleton created using the verbatim +initialize method, Cocoa will attempt to subclass your singleton (and throw an NSInternalInconsistencyException).

  3. That’s a really interesting point. NSKVONotifying_ classes generally hide themselves by overriding -class, but they can’t hide themselves in the +initialize. Yet another reason for the new pattern. Thanks for the insight.

  4. I am working my way through your iOS6 book. For someone not very experienced with GCD Could you explain the syntax for this singleton pattern? thanks.

    • First, you need to understand the “static” keyword. It means that there is only one “once” variable. It is not a local variable to this function, or an instance variable. There is one copy for the entire program. Furthermore, “once” is initialized to all zeros before the program starts running. Both of these are features of C. There’s nothing special here. So no matter how we get to this method, and no matter what thread we’re running on, “once” refers to the same memory.

      dispatch_once does effectively the following:

      lock(token);
      if (! token) {
        ... do the block ...
        token = <something not 0>;
      }
      unlock(token);
      

      Logically it works like the above, but the actual implementations of “lock()” and “unlock()” are insanely fast if token has already been set and there’s no actual blocking. See Jim Dovey’s discussion on how this can be implemented using OSAtomicCompareAndSwapPtrBarrier(), which is probably similar to how dispatch_once is actually implemented, but I haven’t gone and looked.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>