O que você tem é bom, embora você possa mover a declaração da variável global para o método da instância + (o único local em que ela precisa ser usada, a menos que você permita que seja definida também) e usar um nome como + defaultMyClass ou + sharedMyClass para o seu método. + instância não é reveladora de intenção.
Chris Hanson
Como é improvável que a 'resposta' a essa pergunta mude em breve, estou colocando um bloqueio histórico na pergunta. Duas razões 1) Várias visualizações, votos e bom conteúdo 2) Para impedir o ioiô de abrir / fechar. Foi uma ótima pergunta para a época, mas perguntas desse tipo não são apropriadas para o estouro de pilha. Agora temos a Revisão de código para verificar o código de funcionamento. Leve toda a discussão desta questão para esta meta questão .
precisa
Respostas:
207
Outra opção é usar o +(void)initializemétodo A partir da documentação:
O tempo de execução envia initializepara cada classe em um programa exatamente uma vez antes da classe, ou qualquer classe que herda dela, recebe sua primeira mensagem de dentro do programa. (Portanto, o método nunca pode ser chamado se a classe não for usada.) O tempo de execução envia a initializemensagem para as classes de maneira segura para threads. As superclasses recebem essa mensagem antes de suas subclasses.
Se o tempo de execução chamar isso apenas uma vez, o que o BOOL faz? Isso é uma precaução no caso de alguém chamar essa função explicitamente de seu código?
Aftermathew
5
Sim, é uma precaução, pois a função também pode ser chamada diretamente.
Robbie Hanson
33
Isso também é necessário porque pode haver subclasses. Se eles não substituirem +initializesuas superclasses, a implementação será chamada se a subclasse for usada pela primeira vez.
Sven
3
@Paul, você pode substituir o releasemétodo e torná-lo vazio. :)
4
@aryaxt: A partir dos documentos listados, isso já é seguro para threads. Portanto, a chamada é uma vez por tempo de execução. Essa parece ser a solução correta, segura para threads e otimizada de maneira eficiente.
Isso é tudo que você normalmente deve usar para singletons. Entre outras coisas, manter suas classes instanciadas separadamente instantaneamente facilita o teste, porque você pode testar instâncias separadas em vez de ter uma maneira de redefinir seu estado.
31720 Chris Hanson
3
Stig Brautaset: Não, não há problema em deixar de fora os @ sincronizados neste exemplo. Ele está lá para lidar com a possível condição de corrida de dois threads executando esta função estática ao mesmo tempo, ambos passando pelo teste "if (! SharedSingleton)" ao mesmo tempo e resultando em dois [alvos de MySingleton] s. .. O @synchronized {scope block} força esse segundo segmento hipotético a aguardar o primeiro thread sair do {scope scope} antes de poder continuar nele. Eu espero que isso ajude! =)
MechEthan
3
O que impede alguém de ainda criar sua própria instância do objeto? MySingleton *s = [[MySingelton alloc] init];
Lindon fox 28/10/11
11
@lindonfox Qual é a resposta para sua pergunta?
Raffi Khatchadourian
11
@ Raffi - desculpe, acho que devo ter esquecido de colar na minha resposta. Enfim, eu peguei o livro Pro Objective-C Design Patterns for iOSe ele explica como você faz um singelton "estrito". Basicamente, como você não pode tornar privados os métodos de inicialização, é necessário substituir os métodos de alocação e cópia. Portanto, se você tentar fazer algo como [[MySingelton alloc] init]você, receberá um erro em tempo de execução (embora não seja um erro em tempo de compilação, infelizmente). Eu não entendo como todos os detalhes da criação do objeto, mas você implementar + (id) allocWithZone:(NSZone *)zoneo que é chamado emsharedSingleton
lindon fox
59
Pela minha outra resposta abaixo, acho que você deveria estar fazendo:
Não se preocupe com tudo o que você está fazendo acima. Faça seus (espero que extremamente poucos) singletons separadamente instanciados e tenha apenas um método compartilhado / padrão. O que você fez é necessário apenas se você realmente, realmente, quer SOMENTE uma única instância da sua classe. O que você não sabe, esp. para testes de unidade.
Chris Hanson
O problema é que este é o código de exemplo da Apple para "criar um singleton". Mas sim, você está absolutamente certo.
Colin Barrett
11
O código de amostra da Apple está correto se você deseja um singleton "verdadeiro" (ou seja, um objeto que só pode ser instanciado uma vez, sempre), mas como Chris diz, isso raramente é o que você deseja ou precisa, enquanto algum tipo de instância compartilhada configurável é o que você deseja. geralmente quer.
Caso rápido: na execução normal sharedInstancejá foi definida, o whileloop nunca é executado e a função retorna após simplesmente testar a existência da variável;
Caso lento: se sharedInstancenão existir, uma instância é alocada e copiada para ela usando um Compare And Swap ('CAS');
Caso contencioso: se dois encadeamentos tentarem chamar sharedInstanceao mesmo tempo EsharedInstance não existirem ao mesmo tempo, inicializarão novas instâncias do singleton e tentarão colocá-lo na posição CAS. Qualquer que seja o ganhador, o CAS retornará imediatamente, o que perder, libera a instância que acabou de alocar e retorna o (agora definido) sharedInstance. O single OSAtomicCompareAndSwapPtrBarrieratua como uma barreira de gravação para o encadeamento de configuração e uma barreira de leitura do encadeamento de teste.
Isso é um exagero total pela maior parte do tempo que pode ocorrer durante a vida útil de um aplicativo. No entanto, é correto no local, e a técnica de comparar e trocar é uma ferramenta útil para se conhecer, portanto +1.
21310 Steve Madsen
Boa resposta - a família OSAtomic é uma coisa boa a se saber #
Bill
11
@ Louis: Resposta incrível e realmente esclarecedora! Porém, uma pergunta: o que meu initmétodo deve fazer em sua abordagem? Lançar uma exceção quando sharedInstanceé inicializado não é uma boa ideia, acredito. O que fazer então para impedir que o usuário ligue initdiretamente muitas vezes?
matm
2
Geralmente não o impeço. Muitas vezes, existem razões válidas para permitir que o que é geralmente um singleton se multiplique instanciado, o mais comum é para certos tipos de teste de unidade. Se eu realmente quisesse impor uma única instância, provavelmente o método init verificaria se o global existia e, se existisse, liberaria o self e retornaria o global.
Notei que o clang reclama de um vazamento se você não atribuir o resultado [[self alloc] init]ao sharedInst.
Pix0r 6/05/09
Subverter o init como este é uma abordagem IMO bastante feia. Não mexa no init e / ou na criação real do objeto. Se você optar por um ponto de acesso controlado a uma instância compartilhada, enquanto não estiver inserindo singleton no objeto, terá um tempo mais feliz se estiver escrevendo testes etc. Singletons rígidos são muito usados em demasia.
A documentação da Apple recomenda que você verifique o tipo de classe no seu bloco de inicialização. Porque as subclasses chamam a inicialização por padrão. Existe um caso não óbvio em que subclasses podem ser criadas indiretamente através do KVO. Pois se você adicionar a seguinte linha em outra classe:
Eu tenho uma variação interessante no sharedInstance que é seguro para threads, mas não é bloqueado após a inicialização. Ainda não tenho certeza o suficiente para modificar a resposta principal, conforme solicitado, mas apresento para discussão adicional:
// Volatile to make sure we are not foiled by CPU cachesstaticvolatileALBackendRequestManager*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 que é realmente intrigante. Eu poderia usar class_replaceMethodpara se transformar sharedInstanceem um clone de simpleSharedInstance. Dessa forma, você nunca precisaria se preocupar em adquirir uma @synchronizedfechadura novamente.
Dave DeLong
É o mesmo efeito, usar exchangeImplementations significa que, após o init, quando você chama sharedInstance, você está realmente chamando simpleSharedInstance. Na verdade, eu comecei com replaceMethod, mas decidiu que era melhor apenas mudar as implementações ao redor de modo que o original ainda existe, se necessário ...
Kendall Helmstetter Gelner
Em outros testes, não consegui que o replaceMethod funcionasse - em chamadas repetidas, o código ainda chamava o sharedInstance original em vez de simpleSharedInstance. Eu acho que pode ser porque ambos são métodos de nível de classe ... A substituição que usei foi: class_replaceMethod (self, origSel, method_getImplementation (newMethod), method_getTypeEncoding (newMethod)); e algumas variações dos mesmos. Posso verificar o código que publiquei obras e simpleSharedInstance é chamado após a primeira passagem pelo sharedInstance.
Kendall Helmstetter Gelner,
Você pode criar uma versão segura do encadeamento que não pague os custos de bloqueio após a inicialização sem fazer muito trabalho de escassez de tempo de execução. Postei uma implementação abaixo.
Louis Gerbarg 15/03
11
+1 ótima ideia. Eu simplesmente amo as coisas que podemos fazer com o tempo de execução. Mas, na maioria dos casos, isso provavelmente é uma otimização prematura. Se eu realmente tivesse que me livrar do custo da sincronização, provavelmente usaria a versão sem bloqueio da Louis.
Leia o cabeçalho dispatch / once.h para entender o que está acontecendo. Nesse caso, os comentários do cabeçalho são mais aplicáveis que os documentos ou a página de manual.
A única limitação sobre a classe Singleton é que ela é a subclasse NSObject. Mas na maioria das vezes eu uso singletons no meu código, eles são de fato subclasses NSObject, então essa classe realmente facilita minha vida e torna o código mais limpo.
Estou usando o seu NSSingleton para o meu projeto e parece ser incompatível com o KVO. O problema é que o KVO cria subclasse para cada objeto KVO com o prefixo NSKVONotifying_ MyClass . E faz com que o MyClass + inicialize e -init os métodos a serem chamados duas vezes.
Oleg Trakhman
Testei isso no Xcode mais recente e não tive problemas para registrar ou receber eventos do KVO. Você pode verificar isso com o seguinte código: gist.github.com/3065038 Como mencionei no Twitter, os métodos + initialize são chamados uma vez para NSSingleton e uma vez para cada subclasse. Esta é uma propriedade do Objective-C.
kevinlawler
Se você adicionar NSLog(@"initialize: %@", NSStringFromClass([self class]));ao +initializemétodo, poderá verificar se as classes foram inicializadas apenas uma vez.
Você não deseja sincronizar consigo mesmo ... Como o objeto próprio ainda não existe! Você acaba bloqueando um valor de ID temporário. Você deseja garantir que ninguém mais possa executar métodos de classe (sharedInstance, aloc, alocWithZone :, etc), portanto, é necessário sincronizar no objeto de classe:
@implementationMYSingletonstaticMYSingleton* sharedInstance = nil;+( id )sharedInstance {@synchronized([MYSingletonclass]){if( sharedInstance == nil )
sharedInstance =[[MYSingleton alloc ] init ];}return sharedInstance;}+( id )allocWithZone:(NSZone*)zone {@synchronized([MYSingletonclass]){if( sharedInstance == nil )
sharedInstance =[ super allocWithZone:zone ];}return sharedInstance;}-( id )init {@synchronized([MYSingletonclass]){
self =[ super init ];if( self != nil ){// Insert initialization code here}return self;}}@end
O restante dos métodos, métodos de acesso, métodos de mutação etc. devem ser sincronizados automaticamente. Todos os métodos e inicializadores de classe (+) (e provavelmente -dealloc) devem ser sincronizados no objeto de classe. Você pode evitar a sincronização manual se usar as propriedades do Objective-C 2.0 em vez dos métodos de acessador / mutador. Todos object.property e object.property = foo são automaticamente sincronizados com o próprio.
Rob Dotson
3
Por favor, explique por que você acha que o selfobjeto não existe em um método de classe. O tempo de execução determina qual implementação de método chamar com base exatamente no mesmo valor que fornece selfa cada método (classe ou instância).
dreamlax
2
Dentro de um método de classe, selfestá o objeto de classe. Tente você mesmo:#import <Foundation/Foundation.h> @interface Eggbert : NSObject + (BOOL) selfIsClassObject; @end @implementation Eggbert + (BOOL) selfIsClassObject { return self == [Eggbert class]; } @end int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSLog(@"%@", [Eggbert selfIsClassObject] ? @"YES" : @"NO"); [pool drain]; return 0; }
jscs
0
Só queria deixar isso aqui para não perder. A vantagem deste é que ele é utilizável no InterfaceBuilder, que é uma enorme vantagem. Isso é retirado de outra pergunta que eu fiz :
Sei que existem muitos comentários sobre essa "pergunta", mas não vejo muitas pessoas sugerindo o uso de uma macro para definir o singleton. É um padrão tão comum e uma macro simplifica bastante o singleton.
Aqui estão as macros que escrevi com base nas várias implementações de Objc que eu já vi.
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.
*/#defineSingletonInterface(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.
*/#defineSingletonImplementation(TYPE, NAME) \
static TYPE *__ ## NAME; \
\
\
+(void)initialize \
{ \
static BOOL initialized = NO; \
if(!initialized) \
{ \
initialized = YES; \
__ ## NAME = [[TYPE alloc] init]; \} \
} \
\
\
+(TYPE *)NAME \
{ \
return __ ## NAME; \}
Por que uma macro de interface quando está quase vazia? Consistência do código entre os arquivos de cabeçalho e código; manutenção caso você queira adicionar métodos mais automáticos ou alterá-los.
Estou usando o método initialize para criar o singleton, como é usado na resposta mais popular aqui (no momento da redação).
Com os métodos da classe Objective C, podemos evitar o uso do padrão singleton da maneira usual, a partir de:
[[Librarian sharedInstance] openLibrary]
para:
[Librarian openLibrary]
envolvendo a classe dentro de outra classe que apenas possui métodos de classe , para que não haja chance de criar instâncias duplicadas acidentalmente, pois não estamos criando nenhuma instância!
Se o singleton já estiver inicializado, o bloco LOCK não será inserido. A segunda verificação se (! Inicializado) é para garantir que ainda não esteja inicializado quando o encadeamento atual adquire o LOCK.
Eu costumo usar código semelhante ao da resposta de Ben Hoffstein (que também saí da Wikipedia). Eu o uso pelas razões declaradas por Chris Hanson em seu comentário.
No entanto, às vezes tenho a necessidade de colocar um singleton em um NIB e, nesse caso, uso o seguinte:
Seu código não é seguro para threads. Ele usa sincronizado no método de alocação, mas não no método init. A verificação do bool inicializado não é segura para threads.
Mecki 29/06/09
-5
A resposta aceita, embora seja compilada, está incorreta.
+(MySingleton*)sharedInstance
{@synchronized(self)<-------- self does not exist at class scope
{if(sharedInstance == nil)
sharedInstance =[[MySingleton alloc] init];}return sharedInstance;}
De acordo com a documentação da Apple:
... Você pode adotar uma abordagem semelhante para sincronizar os métodos de classe da classe associada, usando o objeto Class em vez de self.
Mesmo se usar auto-obras, não deveria e isso parece um erro de copiar e colar para mim. A implementação correta para um método de fábrica de classe seria:
auto certamente faz existir, escopo de classe. Refere-se à classe em vez da instância da classe. Classes são (principalmente) objetos de primeira classe.
schwa
Por que você coloca @synchroninzed WITHIN um método?
User4951 4/04
11
Como schwa já disse, selfé o objeto de classe dentro de um método de classe. Veja meu comentário para um snippet demonstrando isso.
JSCs
selfexiste, mas usá-lo como o identificador passado para @synchronizedsincronizará o acesso aos métodos da instância. Como @ user490696 aponta, há casos (como singletons) em que é preferível usar o objeto de classe. Do Guia de programação do Obj-C:You can take a similar approach to synchronize the class methods of the associated class, using the class object instead of self. In the latter case, of course, only one thread at a time is allowed to execute a class method because there is only one class object that is shared by all callers.
Respostas:
Outra opção é usar o
+(void)initialize
método A partir da documentação:Então você pode fazer algo parecido com isso:
fonte
+initialize
suas superclasses, a implementação será chamada se a subclasse for usada pela primeira vez.release
método e torná-lo vazio. :)[Fonte]
fonte
MySingleton *s = [[MySingelton alloc] init];
Pro Objective-C Design Patterns for iOS
e ele explica como você faz um singelton "estrito". Basicamente, como você não pode tornar privados os métodos de inicialização, é necessário substituir os métodos de alocação e cópia. Portanto, se você tentar fazer algo como[[MySingelton alloc] init]
você, receberá um erro em tempo de execução (embora não seja um erro em tempo de compilação, infelizmente). Eu não entendo como todos os detalhes da criação do objeto, mas você implementar+ (id) allocWithZone:(NSZone *)zone
o que é chamado emsharedSingleton
Pela minha outra resposta abaixo, acho que você deveria estar fazendo:
fonte
Como Kendall postou um singleton thread-safe que tenta evitar custos de bloqueio, pensei em lançar um também:
Ok, deixe-me explicar como isso funciona:
Caso rápido: na execução normal
sharedInstance
já foi definida, owhile
loop nunca é executado e a função retorna após simplesmente testar a existência da variável;Caso lento: se
sharedInstance
não existir, uma instância é alocada e copiada para ela usando um Compare And Swap ('CAS');Caso contencioso: se dois encadeamentos tentarem chamar
sharedInstance
ao mesmo tempo EsharedInstance
não existirem ao mesmo tempo, inicializarão novas instâncias do singleton e tentarão colocá-lo na posição CAS. Qualquer que seja o ganhador, o CAS retornará imediatamente, o que perder, libera a instância que acabou de alocar e retorna o (agora definido)sharedInstance
. O singleOSAtomicCompareAndSwapPtrBarrier
atua como uma barreira de gravação para o encadeamento de configuração e uma barreira de leitura do encadeamento de teste.fonte
init
método deve fazer em sua abordagem? Lançar uma exceção quandosharedInstance
é inicializado não é uma boa ideia, acredito. O que fazer então para impedir que o usuário ligueinit
diretamente muitas vezes?fonte
[[self alloc] init]
ao sharedInst.Edit: Esta implementação obsoleta com o ARC. Veja como implementar um singleton Objective-C que seja compatível com o ARC? para implementação correta.
Todas as implementações de inicialização que eu li em outras respostas compartilham um erro comum.
A documentação da Apple recomenda que você verifique o tipo de classe no seu bloco de inicialização. Porque as subclasses chamam a inicialização por padrão. Existe um caso não óbvio em que subclasses podem ser criadas indiretamente através do KVO. Pois se você adicionar a seguinte linha em outra classe:
O Objective-C criará implicitamente uma subclasse de MySingletonClass, resultando em um segundo disparo de
+initialize
.Você pode pensar que deve verificar implicitamente a inicialização duplicada no seu bloco init, como tal:
Mas você vai dar um tiro no próprio pé; ou pior, dê a outro desenvolvedor a oportunidade de dar um tiro no próprio pé.
TL; DR, aqui está minha implementação
(Substitua o ZAssert por nossa própria macro de asserção; ou apenas NSAssert.)
fonte
Uma explicação completa do código da macro Singleton está no blog Cocoa With Love
http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html .
fonte
Eu tenho uma variação interessante no sharedInstance que é seguro para threads, mas não é bloqueado após a inicialização. Ainda não tenho certeza o suficiente para modificar a resposta principal, conforme solicitado, mas apresento para discussão adicional:
fonte
class_replaceMethod
para se transformarsharedInstance
em um clone desimpleSharedInstance
. Dessa forma, você nunca precisaria se preocupar em adquirir uma@synchronized
fechadura novamente.Resposta curta: Fabuloso.
Resposta longa: Algo como ....
Leia o cabeçalho dispatch / once.h para entender o que está acontecendo. Nesse caso, os comentários do cabeçalho são mais aplicáveis que os documentos ou a página de manual.
fonte
Eu rolei singleton em uma classe, para que outras classes possam herdar propriedades singleton.
Singleton.h:
Singleton.m:
E aqui está um exemplo de alguma classe, na qual você deseja se tornar único.
A única limitação sobre a classe Singleton é que ela é a subclasse NSObject. Mas na maioria das vezes eu uso singletons no meu código, eles são de fato subclasses NSObject, então essa classe realmente facilita minha vida e torna o código mais limpo.
fonte
@synchronized
é terrivelmente lento e deve ser evitado.Isso funciona em um ambiente sem coleta de lixo também.
fonte
Isso não deve ser seguro e evitar o bloqueio caro após a primeira chamada?
fonte
Aqui está uma macro que eu montei:
http://github.com/cjhanson/Objective-C-Optimized-Singleton
Ele é baseado no trabalho aqui de Matt Gallagher. Mas, alterando a implementação para usar o método swizzling, descrito aqui por Dave MacLachlan, do Google .
Congratulo-me com comentários / contribuições.
fonte
E se
Então você evita o custo da sincronização após a inicialização?
fonte
Para uma discussão aprofundada do padrão singleton no Objective-C, veja aqui:
Usando o padrão Singleton em Objective-C
fonte
KLSingleton
fonte
NSLog(@"initialize: %@", NSStringFromClass([self class]));
ao+initialize
método, poderá verificar se as classes foram inicializadas apenas uma vez.Você não deseja sincronizar consigo mesmo ... Como o objeto próprio ainda não existe! Você acaba bloqueando um valor de ID temporário. Você deseja garantir que ninguém mais possa executar métodos de classe (sharedInstance, aloc, alocWithZone :, etc), portanto, é necessário sincronizar no objeto de classe:
fonte
self
objeto não existe em um método de classe. O tempo de execução determina qual implementação de método chamar com base exatamente no mesmo valor que forneceself
a cada método (classe ou instância).self
está o objeto de classe. Tente você mesmo:#import <Foundation/Foundation.h> @interface Eggbert : NSObject + (BOOL) selfIsClassObject; @end @implementation Eggbert + (BOOL) selfIsClassObject { return self == [Eggbert class]; } @end int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSLog(@"%@", [Eggbert selfIsClassObject] ? @"YES" : @"NO"); [pool drain]; return 0; }
Só queria deixar isso aqui para não perder. A vantagem deste é que ele é utilizável no InterfaceBuilder, que é uma enorme vantagem. Isso é retirado de outra pergunta que eu fiz :
fonte
fonte
Sei que existem muitos comentários sobre essa "pergunta", mas não vejo muitas pessoas sugerindo o uso de uma macro para definir o singleton. É um padrão tão comum e uma macro simplifica bastante o singleton.
Aqui estão as macros que escrevi com base nas várias implementações de Objc que eu já vi.
Singeton.h
Exemplo de uso:
MyManager.h
MyManager.m
Por que uma macro de interface quando está quase vazia? Consistência do código entre os arquivos de cabeçalho e código; manutenção caso você queira adicionar métodos mais automáticos ou alterá-los.
Estou usando o método initialize para criar o singleton, como é usado na resposta mais popular aqui (no momento da redação).
fonte
Com os métodos da classe Objective C, podemos evitar o uso do padrão singleton da maneira usual, a partir de:
para:
envolvendo a classe dentro de outra classe que apenas possui métodos de classe , para que não haja chance de criar instâncias duplicadas acidentalmente, pois não estamos criando nenhuma instância!
Eu escrevi um blog mais detalhado aqui :)
fonte
Para estender o exemplo de @ robbie-hanson ...
fonte
Meu jeito é simples assim:
Se o singleton já estiver inicializado, o bloco LOCK não será inserido. A segunda verificação se (! Inicializado) é para garantir que ainda não esteja inicializado quando o encadeamento atual adquire o LOCK.
fonte
initialized
comovolatile
é suficiente. Consulte aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf .Eu não li todas as soluções, então perdoe se esse código é redundante.
Esta é a implementação mais segura de threads na minha opinião.
fonte
Eu costumo usar código semelhante ao da resposta de Ben Hoffstein (que também saí da Wikipedia). Eu o uso pelas razões declaradas por Chris Hanson em seu comentário.
No entanto, às vezes tenho a necessidade de colocar um singleton em um NIB e, nesse caso, uso o seguinte:
Deixo a implementação de
-retain
(etc.) para o leitor, embora o código acima seja tudo o que você precisa em um ambiente de coleta de lixo.fonte
A resposta aceita, embora seja compilada, está incorreta.
De acordo com a documentação da Apple:
... Você pode adotar uma abordagem semelhante para sincronizar os métodos de classe da classe associada, usando o objeto Class em vez de self.
Mesmo se usar auto-obras, não deveria e isso parece um erro de copiar e colar para mim. A implementação correta para um método de fábrica de classe seria:
fonte
self
é o objeto de classe dentro de um método de classe. Veja meu comentário para um snippet demonstrando isso.self
existe, mas usá-lo como o identificador passado para@synchronized
sincronizará o acesso aos métodos da instância. Como @ user490696 aponta, há casos (como singletons) em que é preferível usar o objeto de classe. Do Guia de programação do Obj-C:You can take a similar approach to synchronize the class methods of the associated class, using the class object instead of self. In the latter case, of course, only one thread at a time is allowed to execute a class method because there is only one class object that is shared by all callers.