J'ai vu la version thread safe
+(MyClass *)singleton { static dispatch_once_t pred; static MyClass *shared = nil; dispatch_once(&pred, ^{ shared = [[MyClass alloc] init]; }); return shared; }
mais que se passerait-il si quelqu'un appelait simplement [MyClass alloc] init]
? Comment faire revenir la même instance que la méthode +(MyClass *)singleton
?
Apple recommand l'implémentation ssortingcte de singleton (aucun autre object vivant du même type n'est autorisé) de cette façon:
+ (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; }
Lien vers la documentation Apple (bas de page, sans ARC)
Cela pourrait être utile,
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; }
J'ai pris cet exemple de code sur le blog du canard: http://www.duckrowing.com/2011/11/09/using-the-singleton-pattern-in-objective-c-part-2/
Dans le .h nous avons
@interface Foo : NSObject + (Foo *) sharedFoo; @end
et dans le .m nous avons
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
Notez le allocWithZone.