Chapter 13: Singleton

The Singleton Pattern seeks to control access to a unique resource by leaving it under the control of a class that by design can have only one instance. Typically, the class stores a pointer to the unique instance as a static variable. The program can then request the pointer from a static member function (in C++) or from a class method (in Objective-C).

Head First Design Patterns also covers the Singleton pattern, although it didn’t provide a compilable, executable example. I created a somewhat contrived example in C++ for that book (leave a comment if you’d like to see it). Cocoa has several examples of the Singleton pattern, including NSApplication.

Quoting the Buck and Yacktman’s book, the three goals a singleton implementation must achieve are

  • Encapsulate a shared resource.
  • Provide a standard way to create one shared instance.
  • Provide a standard way to access the one shared instance.

The book’s Singleton example is a high-score manager for a game, meant to keep track of the highest scores on a particular computer. I first tried writing a command-line application to exercise this code, but the +sharedInstance method looks for a class name in the appliction’s bundle. Creating a bundle for a regular command-line app seemed like to much of a pain, so for try #2 I went with a regular Cocoa app that didn’t do much more than create a shared instance.

The code from the book didn’t work. I put the code in a project, and verified that calling +alloc, +new, etc., didn’t work as planned, however, +sharedInstance didn’t create an instance, either. Calling the superclass’s +alloc called the Singleton’s +alloc instead, which failed as planned.

I added a number of log statements to +sharedInstance to check the class and the superclass. They both returned MYGameHighScoreManager, but somehow, inside +hiddenAlloc, the statement [super alloc] called the MYGameHighScoreManager’s alloc method.

I eventually figured out that NSClassFromString returns a Class, not a Class *. It seems like Class has type id, so it’s already a pointer. I got the program to work by changing [super alloc] to [[super superclass] alloc] in the +sharedInstance of MYGameHighScoreManager. This make sense because +alloc is class method, not an instance method.

To wrap up, here’s the code I wrote to exercise the high score manager class. It goes inside the AppDelegate class.

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
  NSLog(@"Trying +alloc for MYGameHighScoreManager");
  MYGameHighScoreManager *mgr = [[MYGameHighScoreManager alloc] init];
  if (mgr) {
    NSLog(@"+alloc returned an object");
  }
  NSLog(@"Trying +new...");
  mgr = [MYGameHighScoreManager new];
  if (mgr) {
    NSLog(@"+new returned an object");
  }
  NSLog(@"Trying +allocWithZone...");
  mgr = [[MYGameHighScoreManager allocWithZone:nil] init];
  if (mgr) {
    NSLog(@"+allocWithZone: returned an object");
  }
  NSLog(@"Getting the shared instance...");
  mgr = [MYGameHighScoreManager sharedInstance];
  NSLog(@"%@", [mgr description]);
  if (!mgr) {
    NSLog(@"+sharedInstance didn't return an object");
  } else {
    NSLog(@"+sharedInstance worked!\n");
  }
  
}
Advertisements
This entry was posted in Uncategorized and tagged . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s