Comment implémenter correctement la class Singleton sécurisée compatible ARC et `alloc init '?

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.