2008-09-28 2 views
334

Мой одноточечно акцесора обычно некоторый вариант:Каким должен быть мой объектив Objective-C?

static MyClass *gInstance = NULL; 

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

    return(gInstance); 
} 

Что я мог делать, чтобы улучшить это?

+27

Что у вас есть хорошо, хотя вы могли бы переместить глобальную переменную декларацию в ваш + метод экземпляра (единственное место, где она должна быть использованы, если вы не позволяете ему быть установлены, а) и использовать имя типа + defaultMyClass или + sharedMyClass для вашего метода. + экземпляр не предназначен для выявления. – 2008-09-28 09:37:58

ответ

207

Другой вариант заключается в использовании метода +(void)initialize. Из документации:

Среда посылает initialize на каждый класс в программе ровно один раз, как раз перед классом, или любой класс, который наследует от него, посылается первое сообщение из программы. (Таким образом, этот метод никогда не может быть вызван, если класс не используется.) Среда выполнения отправляет сообщение initialize классам в потокобезопасном режиме. Суперклассы получают это сообщение перед их подклассами.

Таким образом, вы могли бы сделать что-то похожее на это:

static MySingleton *sharedSingleton; 

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

Если время выполнения вызовет только один раз, что делает BOOL? Является ли это предосторожностью, если кто-то называет эту функцию явно из своего кода? – Aftermathew 2009-04-03 17:28:14

+5

Да, это предосторожность, так как функция также может быть вызвана напрямую. – 2009-04-08 04:32:59

95
@interface MySingleton : NSObject 
{ 
} 

+ (MySingleton *)sharedSingleton; 
@end 

@implementation MySingleton 

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

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

    return sharedSingleton; 
    } 
} 

@end 

[Source]

+7

Это все, что вы обычно должны использовать для одиночных игр. Помимо прочего, сохранение отдельных классов в отдельности позволяет им легче тестировать, потому что вы можете протестировать отдельные экземпляры, а не иметь способ сбросить свое состояние. – 2008-09-28 09:36:28

14
 
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; 
} 
+3

Я заметил, что clang жалуется на утечку, если вы не назначили результат `[[self alloc] init]` sharedIst. – pix0r 2009-05-06 18:21:47

2

Это работает без мусора, собранной среды также.

@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 
59

За мой другой ответ ниже, я думаю, что вы должны делать:

+ (id)sharedFoo 
{ 
    static dispatch_once_t once; 
    static MyFoo *sharedFoo; 
    dispatch_once(&once,^{ sharedFoo = [[self alloc] init]; }); 
    return sharedFoo; 
} 
+6

Не беспокойтесь о том, что вы делаете выше. Сделайте ваши (надеюсь, очень немногие) одиночные однопользовательские экземпляры отдельно, и просто используйте метод shared/default. То, что вы сделали, необходимо только в том случае, если вы действительно хотите ТОЛЬКО один экземпляр вашего класса. Который вы не делаете, особенно. для модульных испытаний. – 2008-09-28 09:35:06

+0

Дело в том, что это образец кода Apple для «создания одноэлементного». Но да, ты совершенно прав. – 2008-10-23 01:39:16

+1

Пример кода Apple правильный, если вы хотите «истинный» синглтон (т. Е. Объект, который может быть создан только один раз, когда-либо), но, как говорит Крис, это редко то, что вам нужно или нужно, тогда как какой-то настраиваемый общий экземпляр - это то, что вы обычно хотите. – 2009-07-25 01:25:01

-4

Обычно я использую код, примерно такой же, как в ответе Бен Хоффстайна (который я также получил из Википедии). Я использую его по причинам, изложенным Крисом Хэнсоном в его комментарии.

Однако, иногда у меня есть необходимость разместить синглтон в СИБ, и в этом случае я использую следующее:

@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 

Я оставляю реализацию -retain (и т.д.) к читателю, хотя приведенный выше код - это все, что вам нужно в среде сбора мусора.

+2

Ваш код не является потокобезопасным. Он использует синхронизацию в методе alloc, но не в методе init. Проверка инициализированного bool не является потокобезопасной. – Mecki 2009-06-29 12:44:33

0

Вы не хотите синхронизировать себя ... Поскольку самообъект еще не существует! В конечном итоге вы блокируете временное значение id. Вы хотите, чтобы убедиться, что никто не может запускать методы класса (sharedInstance, Alloc, allocWithZone :, и т.д.), так что вам нужно синхронизировать на объект класса вместо:

@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 
+1

Остальные методы, методы доступа, методы мутаторов и т. Д. Должны синхронизировать себя. Все методы класса (+) и инициализаторы (и, вероятно, -dealloc) должны синхронизировать объект класса. Вы можете избежать синхронизации вручную, если используете объекты Objective-C 2.0 вместо методов accessor/mutator. Все объекты object.property и object.property = foo автоматически синхронизируются с самим собой. – 2010-01-13 22:10:43

+3

Пожалуйста, объясните, почему вы думаете, что объект `self` не существует в методе класса. Среда выполнения определяет, какую реализацию метода следует вызывать на основе того же самого значения, которое она предоставляет как «self» для каждого метода (класса или экземпляра). – dreamlax 2010-02-19 06:53:34

9

У меня есть интересная вариация на sharedInstance, который потокобезопасен, но не блокируется после инициализации.Я еще не достаточно уверен, что изменить верхний ответ в соответствии с просьбой, но представить его для дальнейшего обсуждения:

// 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; 
} 
+1

+1 Это действительно интригующе. Я мог бы использовать `class_replaceMethod` для преобразования` sharedInstance` в клон `simpleSharedInstance`. Таким образом, вам больше не придется беспокоиться о том, чтобы снова синхронизировать блокировку @ @ synchronized. – 2010-02-19 06:19:51

+0

Это то же самое, использование exchangeImplementations означает, что после init, когда вы вызываете sharedInstance, вы действительно вызываете simpleSharedInstance. Я действительно начал с replaceMethod, но решил, что было бы лучше просто переключать реализации вокруг, поэтому оригинал все еще существовал при необходимости ... – 2010-02-19 07:46:44

+0

В ходе дальнейшего тестирования я не мог заставить replaceMethod работать - при повторных вызовах код, который все еще называется оригинальный sharedInstance вместо simpleSharedInstance. Я думаю, что это могут быть из-за того, что они оба являются методами уровня класса ... Используемая замена: \t \t \t class_replaceMethod (self, origSel, method_getImplementation (newMethod), method_getTypeEncoding (newMethod)); и некоторые его варианты. Я могу проверить код, который я опубликовал, и simpleSharedInstance вызывается после первого прохода через sharedInstance. – 2010-02-19 07:58:22

2

Here's a macro, что я собрал:

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

Он основан на the work here by Matt Gallagher Но изменение реализации для использования method swizzling as described here by Dave MacLachlan of Google.

Я приветствую комментарии/вклады.

+0

ссылка кажется сломанной - где я могу получить этот источник? – amok 2010-08-29 21:09:48

58

С Kendall posted поточно одноплодной, что попытки избежать блокировки затрат, я думал, что бросить один вверх, а также:

#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;                   
} 

Хорошо, позвольте мне объяснить, как это работает:

  1. Fast case: при нормальном выполнении sharedInstance уже установлен, поэтому цикл while никогда не выполняется, и функция возвращается после простого тестирования существования переменной;

  2. Медленный футляр: Если sharedInstance не существует, экземпляр выделяется и копируется в него с использованием Compare and Swap ('CAS');

  3. Спорный случай: если две нити как попытка вызвать sharedInstance одновременно ИsharedInstance не существует в то же время, то они оба будут инициализировать новые экземпляры одноточечного и попытке CAS в рабочее положение. Независимо от того, какой выигрыш возвращается CAS немедленно, в зависимости от того, кто теряет релизы, экземпляр, который он только что выделил, и возвращает (теперь установленный) sharedInstance. Единственный OSAtomicCompareAndSwapPtrBarrier действует как барьер записи для установочной нити и барьер чтения из тестовой нити.

+18

Это полный переполняющий процесс в течение одного раза, который может произойти во время работы приложения. Тем не менее, это правильно, и метод сравнения и свопинга - полезный инструмент, о котором нужно знать, поэтому +1. – 2010-04-22 14:37:17

2

Нельзя ли быть потоковым и избегать дорогостоящей блокировки после первого звонка?

+ (MySingleton*)sharedInstance 
{ 
    if (sharedInstance == nil) { 
     @synchronized(self) { 
      if (sharedInstance == nil) { 
       sharedInstance = [[MySingleton alloc] init]; 
      } 
     } 
    } 
    return (MySingleton *)sharedInstance; 
} 
+2

. проверенная технология блокировки, используемая здесь, часто является реальной проблемой в некоторых средах (см. http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf или Google). Пока не будет показано иначе, я бы предположил, что Objective-C не является иммунным. Также см. Http://www.wincent.com/a/knowledge-base/archives/2006/01/locking_doublec.php. – 2010-04-22 15:04:20

0
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 
5

Я свернутый синглтон в классе, так что другие классы могут наследует свойства singleton.

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 

А вот пример некоторого класса, который вы хотите стать синглтон.

#import "Singleton.h" 

@interface SomeClass : Singleton { 

} 

@end 

@implementation SomeClass 

DEFINE_SHARED_INSTANCE; 

@end 

Единственное ограничение, связанное с классом Singleton, заключается в том, что это подкласс NSObject.Но чаще всего я использую синглтоны в своем коде, они на самом деле являются подклассами NSObject, поэтому этот класс действительно облегчает мою жизнь и делает код чище.

0

Просто хотел оставить это здесь, чтобы не потерять его. Преимущество этого заключается в том, что его можно использовать в InterfaceBuilder, что является огромным преимуществом. This is taken from another question that I asked:

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; 
} 
-5

Принятый ответ, хотя он и компилируется, неверен.

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

Per Apple, документации:

... Вы можете принять подобный подход, чтобы синхронизировать методы класса соответствующего класса, используя объект класса, а не я.

Даже если вы используете самообслуживание, это не должно быть, и это похоже на ошибку копирования и вставки для меня. Правильное применение для метода класса фабрики будет:

+ (MySingleton*)getInstance 
{ 
    @synchronized([MySingleton class]) 
    { 
     if (sharedInstance == nil) 
      sharedInstance = [[MySingleton alloc] init]; 
    } 
    return sharedInstance; 
} 
12

Edit: Эта реализация с ARC устарел. Пожалуйста, посмотрите на How do I implement an Objective-C singleton that is compatible with ARC? для правильной реализации.

Все реализации инициализации, которые я прочитал в других ответах, имеют общую ошибку.

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

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

Документация Apple рекомендует вам проверить тип класса в вашем блоке инициализации. Поскольку подклассы вызывают инициализацию по умолчанию. Существует неочевидный случай, когда подклассы могут создаваться косвенно через KVO. Ибо если вы добавить следующую строку в другом классе:

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

Objective-C будет неявно создать подкласс MySingletonClass, в результате чего второй запуск +initialize.

Вы можете думать, что вы должны неявно проверить дубликата инициализации в вашем инициализации блока как такового:

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

Но вы будете стрелять себе в ногу; или, что еще хуже, дать другому разработчику возможность стрелять в ногу.

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

TL; DR, вот моя реализация

@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 

(Заменить ZAssert с собственным утверждение макро;. Или просто NSAssert)

0

Я знаю, что есть много замечаний по этот «вопрос», но я не вижу, чтобы многие люди предлагали использовать макрос для определения синглтона. Это такой общий шаблон, и макрос значительно упрощает синглтон.

Вот макросы, которые я написал на основе нескольких реализаций Objc, которые я видел.

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; \ 
} 

Пример использования:

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 

Почему в Int erface macro, когда он почти пуст? Кодовая согласованность между заголовком и файлами кода; ремонтируемость, если вы хотите добавить больше автоматических методов или изменить их.

Я использую метод initialize для создания синглтона, который используется в наиболее популярном здесь ответе (на момент написания).

2

Как насчет

static MyClass *gInstance = NULL; 

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

    return(gInstance); 
} 

Таким образом, вы избежать затрат синхронизации после инициализации?

6

Короткий ответ: Невероятный.

Длинный ответ: Что-то вроде ....

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 

Обязательно прочитайте dispatch/once.h header, чтобы понять, что происходит. В этом случае комментарии заголовка более применимы, чем документы или справочная страница.

0

С Объективными методами класса C, мы можем просто избегать использования одноэлементного рисунка на обычном пути от:

[[Librarian sharedInstance] openLibrary] 

к:

[Librarian openLibrary] 

обертывания класса внутри другого класса, который только имеет Методы класса, таким образом, нет возможности случайно создать повторяющиеся экземпляры, так как мы не создаем какой-либо экземпляр!

я написал более подробный блог here :)

0

Чтобы продлить пример из @ 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; 
} 
1

KLSingleton является:

  1. Subclassible (к п-й степени)
  2. ARC совместимый
  3. Safe с alloc и init
  4. Loaded лениво
  5. резьбовых сейф
  6. безблокировочного (использование + инициализации, не @synchronize)
  7. Макро свободной
  8. Swizzle свободной
  9. Простой

KLSingleton

0

Мой путь прост, как это:

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; 
} 

Если t он singleton уже инициализирован, блок LOCK не будет введен. Вторая проверка, если (! Initialized) заключается в том, чтобы убедиться, что она еще не инициализирована, когда текущий поток получает LOCK.

0

Я не читал все решения, поэтому прощайте, если этот код избыточен.

Это, по моему мнению, самая надежная реализация на потоке.

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

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

    return sharedResourcesObj; 
} 
Смежные вопросы