4

Is there a way to create a Singleton pattern with objective-c, which would enable the client code to get a shared instance of any of it's subclasses?

I tried:

@interface Base : NSObject {}
+(id)instance;
@end

@implementation Base
static id _instance;
+(id)instance {
    if (!_instance) {
        _instance = [[self alloc] init];
    }
    return _instance;
}
@end

But calling any subclass's [AmazingThing instance] only returns the first instance created through this mechanism, no matter what type the _instance is. Any clean workarounds?

Edit

I realized (while replying to a deleted answer) that I can do what I was looking for by changing the implementation to be:

static NSMutableDictionary *_instances;

+(id)instance {
    if (!_instances) {
        _instances = [[NSMutableDictionary alloc] init];
    }
    id instance = [_instances objectForKey:self];
    if (!instance) {
        instance = [[self alloc] init];
        [_instances setObject:instance forKey:self];
    }
    return instance;
}

It now works as expected. Still, I'm interested to know if there's a better way to do this.

JeremyP
  • 84,577
  • 15
  • 123
  • 161
sharvey
  • 7,635
  • 7
  • 48
  • 66

4 Answers4

7

I would do it like this:

+(id) instance
{
    static id theInstance = nil;
    if (theInstance == nil)
    {
        theInstance = [[self alloc] init];
    }
    return theInstance;
}

Of course you'd need that method in every subclass of your base class in order to get a different static variable for each class. But you would create a #define in the base class header:

#define CREATE_INSTANCE           \
+(id) instance                    \
{                                 \
    static id theInstance = nil;  \
    if (theInstance == nil)       \
    {                             \
        theInstance = [[self alloc] init]; \
    }                             \
    return theInstance;           \
}

and then each impementation just has the define in it:

@implementation SubClass

CREATE_INSTANCE

// other stuff

@end
JeremyP
  • 84,577
  • 15
  • 123
  • 161
  • Why did you use [self alloc] instead of [[self class] alloc], with the later, you only need to define the + (id) instance in the base class – onmyway133 Nov 13 '13 at 04:05
  • 2
    Because the receiver `self` is already the class. The reason for redefining the method in every subclass is to get a different static variable for the singleton, not to get an instance based on the subclass, which happens automatically. – JeremyP Nov 22 '13 at 14:14
1

If using Objective-C++ is ok. What you can do is have a meta-programmed C++ class that manages the lifetime of a singleton object. This way you can use the Singleton pattern and access the singleton using Derived* d = Singleton<Derived>::get(). For further reference you can look at http://src.chromium.org/viewvc/chrome/trunk/src/base/singleton_objc.h this is how chrome manages to do it.

shreyasva
  • 13,126
  • 25
  • 78
  • 101
  • Thanks, I'll take a look a it. I wonder what the improvement in memory and performance would be compared to the solution I posted in my update. – sharvey Dec 08 '10 at 01:36
0

Simply use EPPZSingleton.

To create a base class that can have exactly one subclass is straightforward, but when you start to create more and more subclasses, you could expect unwanted behaviour. EPPZSingleton solves this issue by maintain a shared collection of singletons.

Geri Borbás
  • 15,810
  • 18
  • 109
  • 172
0

You can also check DOSingleton at https://github.com/stel/DOSingleton

I'm using the same idea with a global dictionary.

Dmitry
  • 7,300
  • 6
  • 32
  • 55