8

I saw thread safe version

+(MyClass *)singleton {
    static dispatch_once_t pred;
    static MyClass *shared = nil;

    dispatch_once(&pred, ^{
        shared = [[MyClass alloc] init];
    });
     return shared;
}

but what would happen if someone just calls [MyClass alloc] init] ? How to make it return same instance as the +(MyClass *)singleton method?

Dulguun Otgon
  • 1,925
  • 1
  • 19
  • 38

3 Answers3

12

Apple recommends the strict singleton implementation (no other living object of the same type is allowed) this way:

+ (instancetype)singleton {
    static id singletonInstance = nil;
    if (!singletonInstance) {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            singletonInstance = [[super allocWithZone:NULL] init];
        });
    }
    return singletonInstance;
}

+ (id)allocWithZone:(NSZone *)zone {
    return [self singleton];
}

- (id)copyWithZone:(NSZone *)zone {
    return self;
}

Link to the apple documentation (bottom of page, Without ARC)

Jonathan Cichon
  • 4,396
  • 16
  • 19
  • you are already doing a dispatch_once(), is there a need to to do if(!singletonInstance)? I believe the dispatch_once() will handle that for us on top of other things like synchronisation. – pnizzle Jan 09 '15 at 05:21
  • @pnizzle you are right, dispatch_once would be enough, checking the instance before could be faster though. – Jonathan Cichon Jan 21 '15 at 12:47
  • Is `allocWithZone:` deprecated? Looks like that when I try to implement it. – Fogh Mar 04 '15 at 10:34
2

This might be helpful,

static Foo *sharedInstance = nil;

+ (Foo *)sharedInstance {

    if (sharedInstance == nil) {

        sharedInstance = [[super allocWithZone:NULL] init];
    }

    return sharedInstance;
}

+ (id)allocWithZone:(NSZone *)zone {
    @synchronized(self)
    {
        if (sharedInstance == nil) {
            sharedInstance = [super allocWithZone:zone];
            return sharedInstance;
        }
    }
    return nil;
}
Engnyl
  • 1,380
  • 16
  • 24
0

I picked up this code sample from the duckrowing blog: http://www.duckrowing.com/2011/11/09/using-the-singleton-pattern-in-objective-c-part-2/

In the .h we have

@interface Foo : NSObject
+ (Foo *) sharedFoo;
@end

and in the .m we have

static SLFoo *sharedInstance = nil;
static dispatch_queue_t serialQueue;

@implementation Foo

- (id)init
{
    id __block obj;

    dispatch_sync(serialQueue, ^{
        obj = [super init];
        if (obj) {
            ;
        }
    });

    self = obj;
    return self;
}

+ (Foo *) sharedFoo;
{
    static dispatch_once_t onceQueue;

    dispatch_once(&onceQueue, ^{
        if (sharedInstance) {
            return;
        }
        sharedInstance = [[Foo alloc]init];
    });
    return sharedInstance;

}

+ (id)allocWithZone:(NSZone *)zone
{
    static dispatch_once_t onceQueue;

    dispatch_once(&onceQueue, ^{
        serialQueue = dispatch_queue_create("com.mydomain.myApp.SerialQueueFoo", NULL);
        if (sharedInstance == nil) {
            sharedInstance = [super allocWithZone:zone];
        }
    });

    return sharedInstance;
}

@end

Notice the allocWithZone.

Paul Cezanne
  • 8,629
  • 7
  • 59
  • 90
  • First, the behaviour that you are trying to implement is that [[alloc] init] should return the exact same object as + sharedFoo. There are cases like NSFileManager where there is a shared singleton, but [[alloc] init] returns a different instance. In your case, I think you could just put a dispatch_once into init instead of the dispatch_sync, and forget about the allocWithZone. – gnasher729 Mar 11 '14 at 17:53
  • how can you have a singleton with more than one unique instance? – Paul Cezanne Mar 11 '14 at 21:15
  • NSFileManager supplies a _singleton_ that can do most of the things you want to do. It also supplies individual instances that you can modify for more complex situations. So sharedInstance is a singleton, but [[alloc] init] isn't. – gnasher729 Mar 23 '14 at 17:27
  • I understand that, it just isn't a singleton as I know them. Yes, you have easy access to a shared instance, but the singleton design pattern (or anti-pattern!) means one instance. – Paul Cezanne Mar 23 '14 at 23:48