Jak powinien wyglądać mój Objective-C singleton? [zamknięte]

Moja metoda singleton accessor to zazwyczaj jakiś wariant:

static MyClass *gInstance = NULL;

+ (MyClass *)instance
{
    @synchronized(self)
    {
        if (gInstance == NULL)
            gInstance = [[self alloc] init];
    }

    return(gInstance);
}

Co mógłbym zrobić, aby to poprawić?

Author: Rachel, 2008-09-28

26 answers

Inną opcją jest użycie metody +(void)initialize. Z dokumentacji:

Runtime wysyła initialize do każdej klasy w programie dokładnie jeden raz, tuż przed klasą lub jakąkolwiek klasą, która z niej dziedziczy, zostanie wysłana pierwsza wiadomość z programu. (Tak więc metoda nigdy nie może być wywołana, jeśli klasa nie jest używana.) Runtime wysyła wiadomość initialize do klas w sposób bezpieczny dla wątku. Superklasy otrzymują tę wiadomość przed ich podklasami.

Żebyś mógł zrób coś podobnego do tego:

static MySingleton *sharedSingleton;

+ (void)initialize
{
    static BOOL initialized = NO;
    if(!initialized)
    {
        initialized = YES;
        sharedSingleton = [[MySingleton alloc] init];
    }
}
 207
Author: Robbie Hanson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-27 02:14:23
@interface MySingleton : NSObject
{
}

+ (MySingleton *)sharedSingleton;
@end

@implementation MySingleton

+ (MySingleton *)sharedSingleton
{
  static MySingleton *sharedSingleton;

  @synchronized(self)
  {
    if (!sharedSingleton)
      sharedSingleton = [[MySingleton alloc] init];

    return sharedSingleton;
  }
}

@end

[Źródło]

 95
Author: Ben Hoffstein,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-28 04:23:16

Według mojej innej Odpowiedzi poniżej, myślę, że powinieneś zrobić:

+ (id)sharedFoo
{
    static dispatch_once_t once;
    static MyFoo *sharedFoo;
    dispatch_once(&once, ^ { sharedFoo = [[self alloc] init]; });
    return sharedFoo;
}
 59
Author: Colin Barrett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-19 23:24:34

Ponieważ Kendall opublikował threadsafe singleton, który próbuje uniknąć kosztów blokowania, pomyślałem, że wrzucę też jeden:

#import <libkern/OSAtomic.h>

static void * volatile sharedInstance = nil;                                                

+ (className *) sharedInstance {                                                                    
  while (!sharedInstance) {                                                                          
    className *temp = [[self alloc] init];                                                                 
    if(!OSAtomicCompareAndSwapPtrBarrier(0x0, temp, &sharedInstance)) {
      [temp release];                                                                                   
    }                                                                                                    
  }                                                                                                        
  return sharedInstance;                                                                        
}

Ok, pozwól mi wyjaśnić, jak to działa:

  1. Szybki przypadek: w normalnym wykonaniu sharedInstance zostało już ustawione, więc pętla while nigdy nie jest wykonywana, a funkcja powraca po prostu po sprawdzeniu istnienia zmiennej;

  2. Powolna wielkość liter: Jeśli sharedInstance nie istnieje, wtedy instancja jest przydzielana i kopiowana do niej using a Compare And Swap ("CAS');

  3. Jeśli dwa wątki jednocześnie próbują wywołać sharedInstance i sharedInstance nie istnieje w tym samym czasie, a następnie obie zainicjalizują nowe instancje Singletona i spróbują go ustawić na swoim miejscu. Niezależnie od tego, który z nich wygra, CAS zwróci natychmiast, a który przegra, zwolni instancję, którą właśnie przydzielił i zwróci (teraz ustawione) sharedInstance. Pojedynczy OSAtomicCompareAndSwapPtrBarrier działa zarówno jako bariera zapisu dla wątku ustawień, jak i bariera odczytu z wątku testowego.

 58
Author: Louis Gerbarg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:29:47
static MyClass *sharedInst = nil;

+ (id)sharedInstance
{
    @synchronize( self ) {
        if ( sharedInst == nil ) {
            /* sharedInst set up in init */
            [[self alloc] init];
        }
    }
    return sharedInst;
}

- (id)init
{
    if ( sharedInst != nil ) {
        [NSException raise:NSInternalInconsistencyException
            format:@"[%@ %@] cannot be called; use +[%@ %@] instead"],
            NSStringFromClass([self class]), NSStringFromSelector(_cmd), 
            NSStringFromClass([self class]),
            NSStringFromSelector(@selector(sharedInstance)"];
    } else if ( self = [super init] ) {
        sharedInst = self;
        /* Whatever class specific here */
    }
    return sharedInst;
}

/* These probably do nothing in
   a GC app.  Keeps singleton
   as an actual singleton in a
   non CG app
*/
- (NSUInteger)retainCount
{
    return NSUIntegerMax;
}

- (oneway void)release
{
}

- (id)retain
{
    return sharedInst;
}

- (id)autorelease
{
    return sharedInst;
}
 14
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-28 04:46:48

Edit: Ta implementacja jest przestarzała z ARC. Proszę spojrzeć na jak zaimplementować Objective-C singleton, który jest kompatybilny z ARC? do poprawnej realizacji.

Wszystkie implementacje initialize, które czytałem w innych odpowiedziach, mają wspólny błąd.

+ (void) initialize {
  _instance = [[MySingletonClass alloc] init] // <----- Wrong!
}

+ (void) initialize {
  if (self == [MySingletonClass class]){ // <----- Correct!
      _instance = [[MySingletonClass alloc] init] 
  }
}

Dokumentacja Apple zaleca sprawdzenie typu klasy w bloku inicjalizacji. Ponieważ podklasy domyślnie wywołują initialize. Istnieje nieoczywisty przypadek, w którym podklasy mogą być tworzone pośrednio poprzez KVO. Jeśli dodasz następujący wiersz w innej klasie:

[[MySingletonClass getInstance] addObserver:self forKeyPath:@"foo" options:0 context:nil]

Objective-C domyślnie utworzy podklasę MySingletonClass, co spowoduje drugie uruchomienie +initialize.

Możesz pomyśleć, że powinieneś domyślnie sprawdzić duplikat inicjalizacji w bloku init jako taki:

- (id) init { <----- Wrong!
   if (_instance != nil) {
      // Some hack
   }
   else {
      // Do stuff
   }
  return self;
}

Ale strzelisz sobie w stopę, albo co gorsza dasz innemu deweloperowi możliwość strzelania sobie w stopa.

- (id) init { <----- Correct!
   NSAssert(_instance == nil, @"Duplication initialization of singleton");
   self = [super init];
   if (self){
      // Do stuff
   }
   return self;
}

TL; DR, oto moja implementacja

@implementation MySingletonClass
static MySingletonClass * _instance;
+ (void) initialize {
   if (self == [MySingletonClass class]){
      _instance = [[MySingletonClass alloc] init];
   }
}

- (id) init {
   ZAssert (_instance == nil, @"Duplication initialization of singleton");
   self = [super init];
   if (self) {
      // Initialization
   }
   return self;
}

+ (id) getInstance {
   return _instance;
}
@end

(Zastąp ZAssert naszym własnym makrem twierdzenia; lub po prostu NSAssert.)

 12
Author: lorean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:35

Dokładne wyjaśnienie kodu makra Singletona znajduje się na blogu Cocoa With Love

Http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html .

 10
Author: Matthieu Cormier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-12 22:45:37

Mam ciekawą odmianę sharedInstance, która jest bezpieczna dla wątków, ale nie blokuje się po inicjalizacji. Nie jestem jeszcze na tyle pewien, aby zmodyfikować górną odpowiedź zgodnie z żądaniem, ale przedstawiam ją do dalszej dyskusji: {]}

// Volatile to make sure we are not foiled by CPU caches
static volatile ALBackendRequestManager *sharedInstance;

// There's no need to call this directly, as method swizzling in sharedInstance
// means this will get called after the singleton is initialized.
+ (MySingleton *)simpleSharedInstance
{
    return (MySingleton *)sharedInstance;
}

+ (MySingleton*)sharedInstance
{
    @synchronized(self)
    {
        if (sharedInstance == nil)
        {
            sharedInstance = [[MySingleton alloc] init];
            // Replace expensive thread-safe method 
            // with the simpler one that just returns the allocated instance.
            SEL origSel = @selector(sharedInstance);
            SEL newSel = @selector(simpleSharedInstance);
            Method origMethod = class_getClassMethod(self, origSel);
            Method newMethod = class_getClassMethod(self, newSel);
            method_exchangeImplementations(origMethod, newMethod);
        }
    }
    return (MySingleton *)sharedInstance;
}
 9
Author: Kendall Helmstetter Gelner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-19 08:00:33

Krótka odpowiedź: Bajeczna.

Długa odpowiedź: coś w tym stylu....
static SomeSingleton *instance = NULL;

@implementation SomeSingleton

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

+ (id) allocWithZone:(NSZone *)paramZone {
    return [[self instance] retain];
}

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

- (id) autorelease {
    return self;
}

- (NSUInteger) retainCount {
    return NSUIntegerMax;
}

- (id) retain {
    return self;
}

@end

Pamiętaj, aby przeczytać dispatch/raz.header h , aby zrozumieć, co się dzieje. W tym przypadku komentarze nagłówka są bardziej odpowiednie niż dokumenty lub strona podręcznika.

 6
Author: quellish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-08 03:12:32

Przeniosłem singleton do klasy, więc inne klasy mogą dziedziczyć właściwości Singletona.

Singleton.h:
static id sharedInstance = nil;

#define DEFINE_SHARED_INSTANCE + (id) sharedInstance {  return [self sharedInstance:&sharedInstance]; } \
                               + (id) allocWithZone:(NSZone *)zone { return [self allocWithZone:zone forInstance:&sharedInstance]; }

@interface Singleton : NSObject {

}

+ (id) sharedInstance;
+ (id) sharedInstance:(id*)inst;

+ (id) allocWithZone:(NSZone *)zone forInstance:(id*)inst;

@end
Singleton.m:
#import "Singleton.h"


@implementation Singleton


+ (id) sharedInstance { 
    return [self sharedInstance:&sharedInstance];
}

+ (id) sharedInstance:(id*)inst {
    @synchronized(self)
    {
        if (*inst == nil)
            *inst = [[self alloc] init];
    }
    return *inst;
}

+ (id) allocWithZone:(NSZone *)zone forInstance:(id*)inst {
    @synchronized(self) {
        if (*inst == nil) {
            *inst = [super allocWithZone:zone];
            return *inst;  // assignment and return on first allocation
        }
    }
    return nil; // on subsequent allocation attempts return nil
}

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

- (id)retain {
    return self;
}

- (unsigned)retainCount {
    return UINT_MAX;  // denotes an object that cannot be released
}

- (void)release {
    //do nothing
}

- (id)autorelease {
    return self;
}


@end

A oto przykład jakiejś klasy, którą chcesz zostać singletonem.

#import "Singleton.h"

@interface SomeClass : Singleton {

}

@end

@implementation SomeClass 

DEFINE_SHARED_INSTANCE;

@end

Jedynym ograniczeniem klasy Singleton jest to, że jest to podklasa NSObject. Ale większość czasu używam singletons w moim kodzie są w rzeczywistości NSObject podklasy, więc ta klasa naprawdę ułatwiają mi życie i uczynić kod czystszym.

 5
Author: obscenum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-30 10:00:44

To działa również w środowisku nie-śmieci zbierane.

@interface MySingleton : NSObject {
}

+(MySingleton *)sharedManager;

@end


@implementation MySingleton

static MySingleton *sharedMySingleton = nil;

+(MySingleton*)sharedManager {
    @synchronized(self) {
        if (sharedMySingleton == nil) {
            [[self alloc] init]; // assignment not done here
        }
    }
    return sharedMySingleton;
}


+(id)allocWithZone:(NSZone *)zone {
    @synchronized(self) {
        if (sharedMySingleton == nil) {
            sharedMySingleton = [super allocWithZone:zone];
            return sharedMySingleton;  // assignment and return on first allocation
        }
    }
    return nil; //on subsequent allocation attempts return nil
}


-(void)dealloc {
    [super dealloc];
}

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


-(id)retain {
    return self;
}


-(unsigned)retainCount {
    return UINT_MAX;  //denotes an object that cannot be release
}


-(void)release {
    //do nothing    
}


-(id)autorelease {
    return self;    
}


-(id)init {
    self = [super init];
    sharedMySingleton = self;

    //initialize here

    return self;
}

@end
 2
Author: lajos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-10 14:48:40

Czy to nie powinno być threadsafe i uniknąć kosztownego blokowania po pierwszym połączeniu?

+ (MySingleton*)sharedInstance
{
    if (sharedInstance == nil) {
        @synchronized(self) {
            if (sharedInstance == nil) {
                sharedInstance = [[MySingleton alloc] init];
            }
        }
    }
    return (MySingleton *)sharedInstance;
}
 2
Author: Jompe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-17 11:13:55

Oto makro , które złożyłem:

Http://github.com/cjhanson/Objective-C-Optimized-Singleton

[[0]} opiera się na pracy Matta Gallaghera Jednak zmiana implementacji na metodę opisaną tutaj przez Dave ' a Maclachlana z Google .

Zapraszam do komentowania / komentowania.

 2
Author: CJ Hanson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-13 15:25:03

A może

static MyClass *gInstance = NULL;

+ (MyClass *)instance
{
    if (gInstance == NULL) {
        @synchronized(self)
        {
            if (gInstance == NULL)
                gInstance = [[self alloc] init];
        }
    }

    return(gInstance);
}

Więc unikasz kosztów synchronizacji po inicjalizacji?

 2
Author: Tony,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-29 18:32:32

Szczegółowe omówienie wzorca Singletona w Objective-C znajduje się tutaj:

Użycie wzorca Singletona w Objective-C

 2
Author: Fred McCann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-28 02:15:12

KLSingleton to:

  1. Podkategoria (do n-tego stopnia)
  2. Arc compatible
  3. bezpieczne z alloc i init
  4. Loaded leniwie
  5. thread-safe
  6. Lock-free (używa +initialize, nie @synchronize)
  7. makro-free
  8. swizzle-free
  9. proste

KLSingleton

 1
Author: kevinlawler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-11 20:54:30

Nie chcesz synchronizować się na sobie... Ponieważ obiekt jaźni jeszcze nie istnieje! Kończy się zablokowaniem tymczasowej wartości id. Chcesz się upewnić, że nikt inny nie może uruchamiać metod klasy( sharedInstance, alloc, allocWithZone:, itd.), więc musisz zsynchronizować obiekt klasy:

@implementation MYSingleton

static MYSingleton * sharedInstance = nil;

+( id )sharedInstance {
    @synchronized( [ MYSingleton class ] ) {
        if( sharedInstance == nil )
            sharedInstance = [ [ MYSingleton alloc ] init ];
    }

    return sharedInstance;
}

+( id )allocWithZone:( NSZone * )zone {
    @synchronized( [ MYSingleton class ] ) {
        if( sharedInstance == nil )
            sharedInstance = [ super allocWithZone:zone ];
    }

    return sharedInstance;
}

-( id )init {
    @synchronized( [ MYSingleton class ] ) {
        self = [ super init ];
        if( self != nil ) {
            // Insert initialization code here
        }

        return self;
    }
}

@end
 0
Author: Rob Dotson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-13 22:07:14

Chciałem to tu zostawić, żebym go nie zgubił. Zaletą tego jest to, że można go używać w Interfejsiebuilder, co jest ogromną zaletą. to pochodzi z innego pytania, które zadałem :

static Server *instance;

+ (Server *)instance { return instance; }

+ (id)hiddenAlloc
{
    return [super alloc];
}

+ (id)alloc
{
    return [[self instance] retain];
}


+ (void)initialize
{
    static BOOL initialized = NO;
    if(!initialized)
    {
        initialized = YES;
        instance = [[Server hiddenAlloc] init];
    }
}

- (id) init
{
    if (instance)
        return self;
    self = [super init];
    if (self != nil) {
        // whatever
    }
    return self;
}
 0
Author: Dan Rosenstark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:10
static mySingleton *obj=nil;

@implementation mySingleton

-(id) init {
    if(obj != nil){     
        [self release];
        return obj;
    } else if(self = [super init]) {
        obj = self;
    }   
    return obj;
}

+(mySingleton*) getSharedInstance {
    @synchronized(self){
        if(obj == nil) {
            obj = [[mySingleton alloc] init];
        }
    }
    return obj;
}

- (id)retain {
    return self;
}

- (id)copy {
    return self;
}

- (unsigned)retainCount {
    return UINT_MAX;  // denotes an object that cannot be released
}

- (void)release {
    if(obj != self){
        [super release];
    }
    //do nothing
}

- (id)autorelease {
    return self;
}

-(void) dealloc {
    [super dealloc];
}
@end
 0
Author: user370199,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-03 18:40:09

Wiem, że jest wiele komentarzy na temat tego "pytania", ale nie widzę wielu osób sugerujących użycie makra do zdefiniowania Singletona. To taki powszechny wzór, a Makro znacznie upraszcza singleton.

Oto makra, które napisałem na podstawie kilku implementacji obiektów, które widziałem.

Singeton.h

/**
 @abstract  Helps define the interface of a singleton.
 @param  TYPE  The type of this singleton.
 @param  NAME  The name of the singleton accessor.  Must match the name used in the implementation.
 @discussion
 Typcially the NAME is something like 'sharedThing' where 'Thing' is the prefix-removed type name of the class.
 */
#define SingletonInterface(TYPE, NAME) \
+ (TYPE *)NAME;


/**
 @abstract  Helps define the implementation of a singleton.
 @param  TYPE  The type of this singleton.
 @param  NAME  The name of the singleton accessor.  Must match the name used in the interface.
 @discussion
 Typcially the NAME is something like 'sharedThing' where 'Thing' is the prefix-removed type name of the class.
 */
#define SingletonImplementation(TYPE, NAME) \
static TYPE *__ ## NAME; \
\
\
+ (void)initialize \
{ \
    static BOOL initialized = NO; \
    if(!initialized) \
    { \
        initialized = YES; \
        __ ## NAME = [[TYPE alloc] init]; \
    } \
} \
\
\
+ (TYPE *)NAME \
{ \
    return __ ## NAME; \
}

Przykład użycia:

MyManager.h

@interface MyManager

SingletonInterface(MyManager, sharedManager);

// ...

@end

MyManager.m

@implementation MyManager

- (id)init
{
    self = [super init];
    if (self) {
        // Initialization code here.
    }

    return self;
}

SingletonImplementation(MyManager, sharedManager);

// ...

@end

Dlaczego makro interfejsu, gdy jest prawie puste? Spójność kodu między nagłówkiem a pliki kodu; konserwacja w przypadku, gdy chcesz dodać więcej automatycznych metod lub zmienić je.

Używam metody initialize, aby utworzyć singleton, jak jest używany w najpopularniejszej odpowiedzi tutaj (w momencie pisania).

 0
Author: Nate,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-22 20:00:41

Z metodami Objective C class, możemy po prostu uniknąć używania wzorca Singletona w zwykły sposób, z:

[[Librarian sharedInstance] openLibrary]

Do:

[Librarian openLibrary]

Zawijając klasę wewnątrz innej klasy, która ma tylko metody klasy , w ten sposób nie ma szans na przypadkowe utworzenie zduplikowanych instancji, ponieważ nie tworzymy żadnej instancji!

Napisałem bardziej szczegółowy blog tutaj :)

 0
Author: chunkyguy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-10 22:35:08

Aby rozszerzyć przykład z @ robbie-hanson ...

static MySingleton* sharedSingleton = nil;

+ (void)initialize {
    static BOOL initialized = NO;
    if (!initialized) {
        initialized = YES;
        sharedSingleton = [[self alloc] init];
    }
}

- (id)init {
    self = [super init];
    if (self) {
        // Member initialization here.
    }
    return self;
}
 0
Author: JJD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-22 16:52:31

Mój sposób jest prosty:

static id instanceOfXXX = nil;

+ (id) sharedXXX
{
    static volatile BOOL initialized = NO;

    if (!initialized)
    {
        @synchronized([XXX class])
        {
            if (!initialized)
            {
                instanceOfXXX = [[XXX alloc] init];
                initialized = YES;
            }
        }
    }

    return instanceOfXXX;
}

Jeśli singleton jest już zainicjowany, blok blokady nie zostanie wprowadzony. Drugi sprawdź, czy (!initialized) ma na celu upewnienie się, że nie została jeszcze zainicjowana, gdy bieżący wątek uzyska blokadę.

 0
Author: TienDC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-24 06:45:56

Nie przeczytałem wszystkich rozwiązań, więc wybacz, że ten kod jest zbędny.

Jest to moim zdaniem najbardziej bezpieczna implementacja wątku.

+(SingletonObject *) sharedManager
{
    static SingletonObject * sharedResourcesObj = nil;

    @synchronized(self)
    {
        if (!sharedResourcesObj)
        {
            sharedResourcesObj = [[SingletonObject alloc] init];
        }
    }

    return sharedResourcesObj;
}
 0
Author: Zolt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-06 19:56:53

Zwykle używam kodu mniej więcej podobnego do tego w odpowiedzi Bena Hoffsteina (którą też wyciągnąłem z Wikipedii). Używam go z powodów podanych przez Chrisa Hansona w jego komentarzu.

Jednak czasami mam potrzebę umieszczenia Singletona w stalówce i w takim przypadku używam następującego:

@implementation Singleton

static Singleton *singleton = nil;

- (id)init {
    static BOOL initialized = NO;
    if (!initialized) {
        self = [super init];
        singleton = self;
        initialized = YES;
    }
    return self;
}

+ (id)allocWithZone:(NSZone*)zone {
    @synchronized (self) {
        if (!singleton)
            singleton = [super allocWithZone:zone];     
    }
    return singleton;
}

+ (Singleton*)sharedSingleton {
    if (!singleton)
        [[Singleton alloc] init];
    return singleton;
}

@end

Zostawiam implementację -retain (itd.) do czytelnika, chociaż powyższy kod jest wszystkim, czego potrzebujesz w środowisku śmieci.

 -4
Author: Gregory Higley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-24 04:53:41

Przyjęta odpowiedź, mimo że jest kompilowana, jest niepoprawna.

+ (MySingleton*)sharedInstance
{
    @synchronized(self)  <-------- self does not exist at class scope
    {
        if (sharedInstance == nil)
            sharedInstance = [[MySingleton alloc] init];
    }
    return sharedInstance;
}

Na dokumentację Apple:

... Można zastosować podobne podejście do synchronizacji metod klas powiązanych klas, używając obiektu klasy zamiast self.

Nawet jeśli używanie self działa, nie powinno i wygląda to jak błąd kopiowania i wklejania. Poprawną implementacją metody class factory byłoby:

+ (MySingleton*)getInstance
{
    @synchronized([MySingleton class]) 
    {
        if (sharedInstance == nil)
            sharedInstance = [[MySingleton alloc] init];
    }
    return sharedInstance;
}
 -5
Author: deleted_user,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-24 04:56:54