2012年10月8日星期一

Objective-C Singleton

Objective-C Singleton:
Hello fellows,
Due to many emails I have been received on the last months, I decide to create a single article to explain a little bit about the Singleton classes (also known as Singleton Pattern). I’ll focus here on Objective-C and Cocoa approach, however I’ll talk a little bit generally, so you can take the concept to other languages as well.
Let’s start!



Just Give me the Code!

Ok, ok. For who of you that just want the final code without protraction, here is it, you can choose a Xcode template or the pure code:



Xcode template (Xcode 4)



A cool template for Xcode 4 that I created to use over my working machines.
  1. Download the zipped file bellow.
  2. Unzip and copy the “db-in” folder to “/Library/Developer/Xcode/Templates/File Templates”
  3. Open an Xcode project and try to add a new file. You will see a category called “db-in” on the left side, under the iOS platform.
Download Xcode template files

Download now

Xcode Singleton Class template

40kb





Pure code



Here is the code for your header and source files:
Header file (.h)
@interface MySingleton : NSObject

+ (MySingleton *) instance;

@end
Source file (.m)
@interface MySingleton()

// Make any initialization of your class.
- (id) initSingleton;

@end

@implementation MySingleton

- (id) initSingleton
{
 if ((self = [super init]))
 {
  // Initialization code here.
 }

 return self;
}

+ (MySingleton *) instance
{
 // Persistent instance.
 static MySingleton *_default = nil;

 // Small optimization to avoid wasting time after the
 // singleton being initialized.
 if (_default != nil)
 {
  return _default;
 }

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
 // Allocates once with Grand Central Dispatch (GCD) routine.
 // It's thread safe.
 static dispatch_once_t safer;
 dispatch_once(&safer, ^(void)
      {
       _default = [[MySingleton alloc] initSingleton];
      });
#else
 // Allocates once using the old approach, it's slower.
 // It's thread safe.
 @synchronized([MySingleton class])
 {
  // The synchronized instruction will make sure,
  // that only one thread will access this point at a time.
  if (_default == nil)
  {
   _default = [[MySingleton alloc] initSingleton];
  }
 }
#endif
 return _default;
}

- (id) retain
{
 return self;
}

- (oneway void) release
{
 // Does nothing here.
}

- (id) autorelease
{
 return self;
}

- (NSUInteger) retainCount
{
    return INT32_MAX;
}

@end

At a glance

First off, Singleton is a Design Patterns, I know you know some patterns and also use some of them every day in your works. Like MVC (Model View Controller) which all of us use to create our App in Xcode, or also the Delegate Pattern, which Cocoa framework uses largely. So the Singleton is one of those patterns. There are hundreds of patterns, if you want to learn more about Design Patterns I suggest you this book:

http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612
OK, now about Singleton Pattern. It’s simple the concept of instantiate (allocate the necessary memory) for a class once and share this instance with all other classes/functions that need it, making at this form, a single point of access.
There are many discussion about the Singleton, many criticisms and many enthusiasm. In my humble opinion, the Singleton Pattern is very useful to control/manage some global data. Like the user account, for example, specially when some data need a special treatment, like user imagem data.
Anyway, my objective here is just to show you how to create a real Singleton class, using the minimum code as possible and make it thread-safe. Remember that in Objective-C multithreading is always something that we must be aware and think about.

Coding the concept

In theory the code is very simple, instead of allocate and initialize the class, we just call a class method that returns the singleton instance. We can use this approach through all our application:
Simple singleton
// Inside a ClassA, for example.
MySingleton *foo = [MySingleton instance];
[foo setSomeValue:1];

// Inside a ClassB, for example.
MySingleton *foo = [MySingleton instance];
[foo someValue]; // gets the value that was set on ClassA.
It’s important to remember that a singleton class SHOULDN’T BE RELEASED! Using the Cocoa logic, when you call “instance” you are not allocating nor copying any memory, so you shouldn’t release it.
Well, but the memory must be allocated for someone, right? Yes, the memory will be allocated and controlled by the “instance” method. Let’s talk about the singleton lock.

Singleton Lock

We create a kind of lock to make sure our instance will be initialized only once. Like this:
Singleton lock
+ (MySingleton *) instance
{
 // Persistent instance.
 static MySingleton *_default = nil;

 if (_default == nil)
 {
  _default = [[MySingleton alloc] init];
 }

 return _default;
}
This code will work for 99,9% of the time for ALL kind of languages. However, there is a rare kind of situation which this code will fail. We’re talking about the multithreading behavior where two threads try to access the singleton instance AND the singleton is not initialized yet.
In a very rare situation, two threads can try to initialize a singleton at the same time.
In a very rare situation, two threads can try to initialize a singleton at the same time.
Notice that initializing a class is something very fast, could be done in one or two microseconds, however for a multithreading application, this could be time enough to cause a redundant instantiation. As the singleton, usually, is never deallocated, the double memory allocation will represent a leak.
To solve this problem, all that we need is to make sure our singleton lock be thread-safe, that means, only one thread can make the initialization process. At this point, with Objective-C we have many options, let’s see the best one.

Thread Safe

The best and faster approach is using the GCD (Grand Central Dispatch). However the GCD is not available for all iOS versions, just for iOS 4 or later. So we must think in a solution that fits good for all. The “@synchronized” instruction is something that works for all iOS versions, it creates a kind of funnel/queue in which only one thread can run at a time.
The problem with “@synchronized” is that it’s very slow and could make threads run at a synchronized way. So, to avoid unnecessarily wasting time with the @synchronized, let’s create a way to make the things run faster after the singleton being initialized:
Thread safe
+ (MySingleton *) instance
{
 // Persistent instance.
 static MySingleton *_default = nil;

 // Small optimization to avoid wasting time after the
 // singleton being initialized.
 if (_default != nil)
 {
  return _default;
 }

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
 // Allocates once with Grand Central Dispatch (GCD) routine.
 // It's thread safe.
 static dispatch_once_t safer;
 dispatch_once(&safer, ^(void)
      {
       _default = [[MySingleton alloc] init];
       // private initialization goes here.
      });
#else
 // Allocates once using the old approach, it's slower.
 // It's thread safe.
 @synchronized([MySingleton class])
 {
  // The synchronized instruction will make sure,
  // that only one thread will access this point at a time.
  if (_default == nil)
  {
   _default = [[MySingleton alloc] init];
   // private initialization goes here.
  }
 }
#endif
 return _default;
}
@end
Notice that the “if (_default != nil)” is a single check, that runs very very fast and can avoid our code of spending time with unnecessary checks. About the GCD and blocks, it’s a simple piece of code that makes the same thing as the code without GCD. The only difference is that the GCD approach uses the special data type “dispatch_once_t” (a kind of BOOL) to check if the code have been executed before.
If you want more information about GCD and the blocks, here is it:

http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Blocks/Articles/00_Introduction.html

http://developer.apple.com/library/ios/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html

http://developer.apple.com/library/ios/#featuredarticles/Short_Practical_Guide_Blocks/_index.html

Final adjustments

OK, we’re almost done. Now, just to make sure that any other class (including classes from Cocoa framework) will not change the retain count of our singleton class, we can override some methods:
Avoiding changes on memory count
- (id) retain
{
 return self;
}

- (oneway void) release
{
 // Does nothing here.
}

- (id) autorelease
{
 return self;
}

- (NSUInteger) retainCount
{
    return INT32_MAX;
}
The dealloc method is not necessary, because the singleton will never be deallocated. But remember to release and retain the memory for internal variables, by the way this is why @property and @synthesize exist.

Conclusion

Very well, my friends, that is all about Singleton Pattern for Obj-C. I hope you liked. Enjoy your singletons and feel free to ask anything you want.
Cya!