Singleton classes are an important concept to understand because they exhibit an extremely useful design pattern. This idea is used throughout the iPhone SDK, for example, UIApplication has a method called sharedApplication which when called from anywhere will return the UIApplication instance which relates to the currently running application.

You can implement a singleton class in Objective-C using the following code:

MyManager.h

#import <foundation/Foundation.h>

@interface MyManager : NSObject {
    NSString *someProperty;
}

@property (nonatomic, retain) NSString *someProperty;

+ (id)sharedManager;

@end

MyManager.m

#import "MyManager.h"

static MyManager *sharedMyManager = nil;

@implementation MyManager

@synthesize someProperty;

#pragma mark Singleton Methods
+ (id)sharedManager {
	@synchronized(self) {
		if(sharedMyManager == nil)
			sharedMyManager = [[super allocWithZone:NULL] init];
	}
	return sharedMyManager;
}
+ (id)allocWithZone:(NSZone *)zone {
	return [[self sharedManager] retain];
}
- (id)copyWithZone:(NSZone *)zone {
	return self;
}
- (id)retain {
	return self;
}
- (unsigned)retainCount {
	return UINT_MAX; //denotes an object that cannot be released
}
- (void)release {
	// never release
}
- (id)autorelease {
	return self;
}
- (id)init {
	if (self = [super init]) {
		someProperty = [[NSString alloc] initWithString:@"Default Property Value"];
	}
	return self;
}
- (void)dealloc {
	// Should never be called, but just here for clarity really.
	[someProperty release];
	[super dealloc];
}

@end

Then you can reference the singleton from anywhere by calling the following function:

MyManager *sharedManager = [MyManager sharedManager];

I’ve used this extensively throughout my code for things such as creating a singleton to handle CoreLocation or CoreData functions.

EDIT: Added property to MyManager.
EDIT: Updated as per Apple’s guidelines to pass static analysis.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • LinkedIn
  • Twitter

67 Responses to “Singleton Classes”

  1. Tommy says:

    Shouldn’t “static ExternalDataManager” be “static MyManager” ?

  2. Oops yes, thanks for spotting that! I’ve changed it now accordingly.

  3. mikew909 says:

    thanks a lot!! just what i was after , great work!

  4. Chris says:

    Is there anything to be aware of if I made a Singleton class like your example, but then subclassed it? e.g.

    #import
    #import “Singleton.h”

    @interface CodeDecodeUSStates : Singleton {

    }

    @end

    and then add any particular methods to the subclass to do various things. I assume those methods would be -(id) operation type? (as opposed to the class side + ).

    and, should I worry about this warning when I tried this:

    CodeDecodeUSStates *p = [CodeDecodeUSStates sharedInstance]; // Used sharedInstance instead of sharedManager

    tia

  5. Chris says:

    Oops, the warning I get (build time) is
    initialization from distinctive Objective-C type
    on the assignment

  6. Hi Chris,

    That warning will be because you need to do:
    CodeDecodeUSStates *p = (CodeDecodeUSStates*)[CodeDecodeUSStates sharedInstance];

    That’s just because sharedInstance returns id, rather than CodeDecodeUSStates. You can ignore the warning, but it’s probably best to cast anyway as it’s better practice to do that.

    As for subclassing, that’s fine and you can add instance or class methods to the subclass and they will work just fine.

    Thanks for reading my tutorial!

  7. Corbin says:

    I’m new to Objective-C. How would I go about storing various variables into this, so I could access them in other views.

    Example of PHP:
    global $fruit;
    $fruit = ‘apples’;

    Instinctively I would try (but this doesn’t work):
    #import MyManager.h
    [MyManager *sharedManager = [MyManager sharedManager]
    [sharedManager.fruit retain:@"apples"]

  8. Hi Corbin,

    If you wanted to do what you’re trying, then you would add a property to MyManager called fruit (probably an NSString) and then you could do:

    MyManager *sharedManager = [MyManager sharedManager];
    sharedManager.fruit = @"apples";

    That would then set the fruit property to ‘apples’.

    If you’re wondering how to add a fruit property:

    #import <Foundation/Foundation.h>
     
    @interface MyManager : NSObject {
       NSString *fruit;
    }
     
    @property (nonatomic, retain) NSString *fruit;
     
    + (id)sharedManager;
     
    @end

    And then @synthesize it in the MyManager.m.

    Does that help at all?

  9. iPhone2020 says:

    Good post Matt. In the above post you showed to define fruit property which is of type NSString. I want to use a NSInteger in my code. When i use it in similar way it gives me an error “property “my variable name” with retain attribute must be of object type.

    I also would like to know how to define these variables with some value in singleton class. For example
    You showed to define fruit in MyManager above, is there a way to set some value to it
    fruit = Mango

    and then change it using
    MyManager *sharedManager = [MyManager sharedManager];
    sharedManager.fruit = @”apples”;

    Thanks

  10. admin says:

    NSInteger is a typedef to int so it’s not an object type. For that reason you would do:

    @property (nonatomic) NSInteger integerValue;

    i.e. not a pointer and not retain on the property.

    Also, if you wanted to set the default of `fruit’ to be `mango’ then you’d just set it to be so in the init method.

  11. Jeff says:

    Thank you very much for posting this. I’m new to Objective-C and I know of the design pattern, but the implementation was hanging me up. I want a singleton to control the access to the application save data file that I will use to return the user to where they left off if a call should interrupt the application.

  12. Rob says:

    Unfortunately the method for casting a subclassed singleton to the child class doesn’t work for me.

    Here is my code:

    NSLog([(GameModel *)[GameModel instance] status]);

    The ‘GameModel’ singelton subclasses the ‘Singleton’ singleton. I get an error as soon as I try to call the instance method ’status’ on GameModel, even though I am casting the returned id to GameModel. A method on the parent class works fine.

    “*** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘*** -[Singleton status]: unrecognized selector sent to instance 0×44627d0′”

  13. Rob,

    Umm that’s sort of fair enough though. Using my way of doing singletons you cannot subclass them unfortunately. That’s because your base Singleton class will have create a static which cannot be shared between the various subclasses.

    You’ll need to copy the singleton code for each subclass you want to create unfortunately.

  14. Rob says:

    Thanks for your quick reply Matt.

    Yes it looks like Singletons are not subclassable in Obj-C which is a pity, since I often use that design pattern to create project-specific versions of managers (or even a projects MVC model which subclasses a generic model).

    I’ve found a half way solution if I don’t want to actually instantiate singletons higher up the inheritance chain. I only reproduce the 2 static methods and the static variable in the lowest class. I can then inherit other methods from all the way up the chain.

  15. Hi Rob,

    Using inheritance on a singleton really doesn’t make sense. If you really want the ease of coding where you don’t want to keep typing / copy&pasting the singleton methods then you could put all the singleton methods into a #define and use that. You could do something along the lines of:

    #define make_singleton ( x ) \
    static MyManager *shared##x = nil; \
    + (id)sharedManager { \
    	@synchronized(self) { \
    		if(shared##x == nil) \
    			[[self alloc] init]; \
    	} \
    	return shared##x; \
    }

    …and then do something like:

    @implementation DataManager
    make_singleton (DataManager)
    @end

    (I haven’t tested that by the way!)

    That might be easier for you?

  16. MattMac says:

    Hi I have followed the code above for my own app. I have declared the sharedManager in one of my view controllers which is correct. I have tried to access the variable in a different controller however the NSLog is showing the value to read

    MyManager *sharedManager = [MyManager sharedManager];
    NSLog(@”test%@”, sharedManager);

    Where am I going wrong?

  17. Hi MattMac,

    What is it showing in another view? It really should work if you’ve followed my guide. The value from that NSLog line should show the same when called from any view. It should show a MyManager which has the same memory address no matter where you call it from.

    Can you elaborate on your problem some more?

  18. Jake says:

    Hi
    I am trying to set a NSString in the singleton to be a text fields text. The code I am using is

    MyManager *sharedManager = [MyManager sharedManager];
    sharedManager.theString = textField.text;

    I am trying to set a label in a different view controller to this text by using this code:

    MyManager *sharedManager = [MyManager sharedManager];
    shower.text = sharedManager.theString;

    I have set up an NSLog to log the text of sharedManager.theString, but everytime it returns NULL. How can I fix this?

  19. @Jake Hmm that is odd. Is the label being set after the string is set? Also, try setting theString to a default value in the MyManager initialiser. Also, try logging theString after setting it to the textField.text value to see if it made it in OK (i.e. the property is set up OK on MyManager).

  20. Jake says:

    what method should i set the initial value in? when i put it in

    + (id)sharedManager {

    or

    + (id)allocWithZone:(NSZone *)zone {

    i get a warning

  21. @Jake – To set the initial value you should create an init function like so:

    - (id)init {
        if(self = [super init]) {
            theString = @"Default Value";
        }
        return self;
    }

    You can’t set in sharedManager or allocWithZone as they are class methods (+) rather than instance methods (-) so they have no idea what self.theString is.

  22. Jake says:

    im using this code

    -(id)init {
    if(self = [super init]) {
    theString = @”hello”;
    }
    return self;
    }

    in MyManager and in the view controller i am using:

    Singleton *sharedManager = [Singleton sharedManager];
    NSLog(@”%@”, sharedManager.theString)

    and every time it returns NULL!!!! wat am i donig wrong???!!!!!

  23. @Jake – If you’d like, send me the XCode project to matt at galloway dot me dot uk and I’ll try to solve it for you.

  24. Joe Schorn says:

    Thanks a bunch. This came in very helpful in a project I’m currently working on.

  25. Matt Guest says:

    Hi everyone, I have found this guide very useful. However I have a small problem.

    I added a property in the fruit example above to MyManager and I can access that as I wish from other classes. However, in the exact same way I added a 2nd property and I get a ‘error: request for member in something not a structure or union’ error on compiling.

    Hmmm, I thought, perhaps you can only use one property in the MyManager class. As a test I replaced the code from the first property with the property of the second. Exactly the same problem. I fear I am missing something elementary out, but can anyone think what the issue may be? I’ve been on this all day.

    Many Thanks in advance
    Matt

  26. Matt Guest says:

    Furthermore to the problem above I have realised that the property is passed successfully to one viewcontroller class, but not to another. Both classes have identical code for retrieving the properties value and have imported the MyManager.h. One returns correctly and the other returns null…

    View 1 doesnt retrieve the property, view 2 does.
    The property is set to MyManager in the RootViewController, which pushes View 1. View 2 is pushed by View 1.

    I think I’m clearly making a big mistake somewhere and my head is fried!!

  27. @Matt – if you send over your code then I can take a look for you if you like? You could either send the whole project folder, or just the MyManager.(h/m).

  28. Ty says:

    Quick question: How do you release the single alloced instance?

  29. @Ty put simply, you don’t. And that’s the point about the Singleton class idea. You don’t need tonrelease it. You could if you want to put in a method on the class to reset it where you release the static variable and then set the static to nil.

  30. Ty says:

    Yes, I understand. Let it get handled when the app closes.

  31. Florian Wagner says:

    Hey folks! I used exactly the same singleton pattern as statet above and got an NSString ( NSString *dbPath; ) and an NSInteger test;
    with

    @property (nonatomic, retain) NSString *dbPath;
    @property (nonatomic, readwrite) NSInteger test;

    The String should keep my database path. Running the dbPath function and setting it with self.dbPath and the self.test works fine but when I access the singleton class from a view controller my set integer value is present but the NSString seems to have already been released => It shows an “Out of scope”

    Any suggestions? Do you need more information? Anybody with the same error? The thing is I am using EXACTLY the same SingletonClass in another application and the string and integer values are stored and accessable without any problems…

  32. @Florian – The NSString is an object, the NSInteger isn’t – it’s an int. This might be why you’re seeing the difference. It does seem odd though that it’s working in one app and not the other :-S. Could you share any more code with us at all?

    One thing I’d suggest is to check that you’re not releasing the NSString too many times. Perhaps even change that property to (nonatomic, copy) to make it copy the value you set rather than retaining the one you pass in.

  33. Thanks so far Matt,
    I am actually at an exebition far away from my MAC but I can share some more code when I come back in 10 days.
    I have actually outcommened with // any release of the strings and the object for it is a singlton can never be released, right…
    It’s so strange. I also changed the properties as you recomended but they still disappear.
    Have any suggestions at which point the NSString object might be autoreleased by the singlton pattern found on apples developer website???

  34. @Florian – Make sure that when you set the string, you’re retaining it in the singleton. You can either have the property set to assign or copy to achieve this but I usually use copy for NSStrings.

    So one of these 2:

    @property (nonatomic, retain) NSString *myString;
    @property (nonatomic, copy) NSString *myString;

    Then you would make sure to @synthesize them in the implementation and use the setter method:

    mySingleton.myString = @"Some string";
    [mySingleton setMyString:@"Some string"];

    Does that help?

  35. Erik Oberhausen says:

    Matt this post has been a huge help. I am a newbie with obj c and have been having problems using the appDelegate method to access the Model data. This makes more sense to me and playing around with it so far, it seems quite powerful and capable.
    One part I am still trying to wrap my brain around is how using this method sits within MVC. Declaring (or populating) properties within the singleton, it seems a bit that the Model class no longer is actually the source for the application’s data.

    Any thoughts on making this point more clear would be appreciated.

    Thanks again for this excellent post!

  36. I’m new at Obj-C. :(

    I got your code working, and added a property for NSInteger. Got it synthesized and working in a viewDidLoad method on the UIView I’m working on:

    // Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
    - (void)viewDidLoad {
    [super viewDidLoad];

    MyManager *sharedManager = [MyManager sharedManager];
    sharedManager.currentGem = 0;

    NSLog(@”current gem from manager is set to %i “, sharedManager.currentGem);

    }

    It writes 0 to the log, as expected. But then I tried this, up higher in the same file, inside and IBAction method:

    - (IBAction)touchButton:(id)sender {

    sharedManager.currentGem = [sender tag];

    }

    When I build, I get the error “’shared manager’ undeclared”

    When I read this article, my base assumption is that this is exactly what would not happen.

    How and were do I instantiate myManager so I can read / write values from anywhere?

    Thanks!

    Doug

  37. I also tried instatiating this in main.m, not just my UIView class:

    #import
    #import “MyManager.h”

    int main(int argc, char *argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, nil);

    MyManager *sharedManager = [MyManager sharedManager];
    sharedManager.currentGem = 0;

    NSLog(@”current gem from manager is set to %i “, sharedManager.currentGem);

    [pool release];
    return retVal;
    }

    I get the same error in the IBAction method mentioned above…

    What next?

  38. @Douglas:

    This code is wrong:

    - (IBAction)touchButton:(id)sender {
    sharedManager.currentGem = [sender tag];
    }

    This is because what is sharedManger? It’s not defined in that scope. You need to do this:

    - (IBAction)touchButton:(id)sender {
    [MyManager sharedManager].currentGem = [sender tag];
    }

    Or alternatively, store a reference to [MyManager sharedManager] in the class, but that defeats the point slightly of using the singleton pattern.

    Does that make sense?

  39. seycho1981 says:

    Hi Matt,

    I have used your Singleton class and it has been very helpful. But I just tried to add a new property like:

    NSMutableArray *photoArray;

    @property (nonatomic, retain) NSMutableArray *photoArray;

    In a viewController I want to add values to that array. This is what I have tried:

    MyManager *sharedManager = [MyManager sharedManager];
    // first try:
    //[sharedManager.photoArray insertObject:[UIImage imageNamed:@"photo-32x32.png"] atIndex:0];
    // Second try
    [sharedManager.photoArray addObject:[UIImage imageNamed:@"photo-32x32.png"]];

    None of the two statements adds the object to the photoArray.
    Again, for the rest of the properties that I have, I’m able to store the data. The problem is just with the NSMutableArray
    Do you have any suggestion?

  40. @seycho1981 – Have you alloc’ed and initialised the NSMutableArray within MyManager anywhere? You should create an init method which does this, like so:

    - (id)init {
        if(self = [super init]) {
            photoArray = [[NSMutableArray] alloc] initWithCapacity:0];
        }
    }
  41. seycho1981 says:

    Thank you!
    That was the problem. I forgot to initialized the array.

  42. Adam says:

    Great tutorial. Thanks for posting. It solved my problem.

  43. Takashi says:

    This tutorial was a huge help, thanks for writing it up

  44. [...] is a full implementation of a Singleton which can be used, but there are arguments that in some instances (like Unit Testing) you would [...]

  45. Josh says:

    First off, I must say that I love you. This is the best solution I have found yet for some of my issues. But still on problem of mine is unsolved
    This works great!
    NSLog(@”TextFieldOutput: %@”, sharedManager.textfieldoutput);

    This returns jiberish. What is my problem?
    CGContextShowTextAtPoint(context, 100.0, 190.0, sharedManager.textfieldoutput, strlen(sharedManager.textfieldoutput));

  46. @Josh – CGContextShowTextAtPoint takes a C style string. Do you need to do [sharedManager.textfieldoutput cString] and also need to use cStringLength as well. Although really you should use cStringUsingEncoding as well. I suggest you look at the NSString docs.

  47. Stephen Korow says:

    This is extermely helpful. Thanks. And thanks for following up on the postings to answer questions.

  48. Joe says:

    Thank you so much for providing this Matt– I’ve been trying to wrap my head around singleton implementation in objc and this post (and especially your responses!) have helped a whole lot.

    One thing I am not sure about is memory management using the singleton.

    If I do:

    sharedManager.fruit = @”apples”;

    and later do:

    sharedManager.fruit = @”pears”;

    Has this caused a leak (since I’m redefining ‘fruit’ w/o releasing it)? I’m not sure exactly where I’d release it if that does indeed leak.

    Again, many thanks!

  49. @Joe – No problem, thanks for reading.

    With regard to the leaking – that’s not specific to the singleton pattern but rather a general Obj-C memory management problem.

    It all boils down to what your @property definitions are. If you’ve got copy or retain, then you won’t be leaking because the setters and getters will handle all of the retain/release logic for you. For a bit more information on this, see here:
    http://stackoverflow.com/questions/387959/nsstring-property-copy-or-retain

  50. Fred McCann says:

    I’ve written up an in-depth discussion of the singleton pattern here:

    http://www.duckrowing.com/2010/05/21/using-the-singleton-pattern-in-objective-c/

Leave a Reply