6 Comments

Summary:

Managing an application’s state can sometimes require complex interaction with persistence and messaging with various resources, or it can be as simple as keeping track of a counter from one view to the next.

Managing an application’s state can sometimes require complex interaction with persistence and messaging with various resources, or it can be as simple as keeping track of a counter from one view to the next.

Two popular techniques to pass references to objects from one view to the next are to create properties in the Application Delegate, or to continue to pass references from one view to the next like a relay race passes a baton from one runner to the next using a series of carefully placed update methods making for an allocation nightmare and increase the opportunities for memory leaks or the hard to track down crashes. Sometimes this need in programming is referred to as implementing Global Variables. There is also a well established design pattern that can assist with this need as well, it is called the Singleton Pattern.

Singleton Pattern

The Singleton Pattern is a derivative of the Factory Pattern that ensures that one and only one instance of an Object can ever exist. By creating one or more implementations of the Singleton Pattern within a given application, the concept of ‘global variables’ can better be managed through tighter control. This allows for what is called lazy instantiation. If you do not need the variable based on what is going on in the application, then do not ask for or create an instance of one.  In Objective-C, Apple has outlined the recommended technique for implementing the singleton pattern.

Objective-C Singleton Pattern

Objective-C Singleton Pattern

static MySingletonClass *sharedGizmoManager = nil;
(MySingletonClass*)sharedManager{
  if (sharedSingletonManager == nil) {
    sharedSingletonManager = [[super allocWithZone:NULL] init];
  }
  return sharedGizmoManager;
}
(id)allocWithZone:(NSZone *)zone{
  return [[self sharedManager] retain];
}
(id)copyWithZone:(NSZone *)zone{
  return self;
}
(id)retain{
  return self;
}
(NSUInteger)retainCount{
  return NSUIntegerMax;
}
(void)release{
  //do nothing
}
(id)autorelease{
  return self;
}

But you may find that the following is all that is necessary:

Singleton.h

#import <Foundation/Foundation.h>
@interface Singleton : NSObject {
}
+ (Singleton*) retrieveSingleton;
@end

Singleton.m

#import "Singleton.h"
@implementation Singleton
static Singleton *sharedSingleton = nil;
+ (Singleton*) retrieveSingleton {
  @synchronized(self) {
    if (sharedSingleton == nil) {
      sharedSingleton = [[Singleton alloc] init];
    }
  }
  return sharedSingleton;
}
+ (id) allocWithZone:(NSZone *) zone {
  @synchronized(self) {
    if (sharedSingleton == nil) {
      sharedSingleton = [super allocWithZone:zone];
      return sharedSingleton;
    }
  }
  return nil;
}
@end

Try and keep each singleton’s scope limited to manage only the information that is related to a particular use case and not as a catch-all for all global information across the application. It is probably best to utilize each singleton as a delegate to the information it is responsible for managing, and not use it as a means to gain access to any objects it has associations with. Although on the iPhone, and when being used in primarily a read only or a write seldom implementation, the risk of writing code that is not thread safe increases when utilizing shared objects. Keeping concurrency in mind, and utilizing the singleton as a delegate to the information at hand, one can watch out for multi thread related issues and deal with them in kind. One thing to watch out for would be include updating or setting properties of the singleton from within an implemented perform selector or a notification. If concurrency issues do arise, it may become necessary to synchronize access to certain properties or methods.

No, not the AppDelegate!

So why not just keep adding properties to the AppDelegate? After all, the AppDelegate is a singleton as well and is therefore accessible by invoking the sharedApplication class method. The problem with this techniques is that you end up loading up the application with too much information that may or may not be necessary depending on what functions the user chooses to evoke. It could also lead to longer and longer startup times. Get the application started as quickly as possible, and don’t leave the user hanging for too long.

What about Global Constants?

Keep in mind that this is not the best technique to employ if all you need is a means to define and gain access to Global Constants. The quickest way to do that is to create a Precompiled Prefix Header file and include that in your project. By default, most of the projects generated in XCode that create iPhone Applications will include a file with an extension of .pch. This file will initially look like the following:

#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#endif

One can then add any number of #define statements that will be included in all header files across the entire project.

#define SOME_STRING_CONSTANT @"My Important String"

Conclusion

The Singleton Pattern can be used to make the complex and ugly means of sharing a simple variable between two different views or view controls an easy task. If used sparingly and some basic guidelines are followed as not to bloat the application and create a multi thread nightmare to debug, this technique can be quite useful. Much more so than passing Objects back and forth among views or by breaking the encapsulation of the AppDelegate by assigning it more responsibility than it should have.

References

You're subscribed! If you like, you can update your settings

  1. Excellent article and very timely (almost) as I have just finished implemented a “Recently Viewed” table view controller in an App I am making to learn about table view. I struggled for awhile with a singleton but could never the array it needed to track persist, it seemed that I was not getting a singleton but a duo! Not terribly useful.

    As I only needed 1 array to keep a list of references to recently viewed objects I just added the array to the AppDelegate and went from there. The trick was telling the table view to reload in the “viewWillAppear” method.

    Great article, hope to see more of these :)

  2. There’s a similar writeup at http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html which includes a macro you can use to turn your class into a singleton with one extra line in your class implementation.

  3. The thing about your singleton, as opposed to Apples, is that you assume you are being called by competent coders.

    Apple effectively “nop out” the retain and release messages, presumably on the assumption that people using the singleton might accidentally unbalance their retain/release calls and subsequently crash.

    Its nanny-coding and its stupid, but they recommended it.

  4. Can you pls explain what is NSZone? Why is allocWithZone method required? Is the user suppose to call it? if so, how?

  5. I have used a singleton interface in my iphone ios 3.0 application. My singleton interface don’t have dealloc implemented. Whenever i run it with performance tools, the instrument shows me memory leaks in singleton interface. How do i prevent the memory leaks.

  6. uh ok, so where do we define our variables?

    Where do we instantiate the object?

    how do we set values in the object?

    how do we get values in the object?

Comments have been disabled for this post