Qual é o motivo exato do uso de dispatch_once no acessador de instância compartilhada de um singleton no ARC?
+ (MyClass *)sharedInstance
{
// Static local predicate must be initialized to 0
static MyClass *sharedInstance = nil;
static dispatch_once_t onceToken = 0;
dispatch_once(&onceToken, ^{
sharedInstance = [[MyClass alloc] init];
// Do any other initialisation stuff here
});
return sharedInstance;
}
Não é uma má idéia instanciar o singleton de forma assíncrona em segundo plano? Quero dizer, o que acontece se eu solicitar essa instância compartilhada e confiar nela imediatamente, mas o dispatch_once leva até o Natal para criar meu objeto? Não retorna imediatamente, certo? Pelo menos, esse parece ser o objetivo principal do Grand Central Dispatch.
Então, por que eles estão fazendo isso?
ios
objective-c
singleton
automatic-ref-counting
Membro orgulhoso
fonte
fonte
Note: static and global variables default to zero.
Respostas:
dispatch_once()
é absolutamente síncrono. Nem todos os métodos GCD fazem as coisas de forma assíncrona (caso em questão,dispatch_sync()
é síncrona). O uso dedispatch_once()
substitui o seguinte idioma:O benefício
dispatch_once()
disso é que é mais rápido. Também é semanticamente mais limpo, porque também protege você de vários threads executando alocação init de sharedInstance - se todos tentarem ao mesmo tempo. Não permitirá que duas instâncias sejam criadas. A idéia todadispatch_once()
é "executar algo de uma vez e apenas uma vez", que é precisamente o que estamos fazendo.fonte
dispatch_once()
é realmente simples (especialmente porque o Xcode o completa automaticamente em um snippet de código completo para você) e significa que você nunca precisa considerar se o método precisa ser seguro para threads.+initialize
acontece antes que a classe seja tocada, mesmo que você ainda não esteja tentando criar sua instância compartilhada. Em geral, a inicialização lenta (criando algo apenas quando necessário) é melhor. Segundo, mesmo sua reivindicação de desempenho não é verdadeira.dispatch_once()
leva quase exatamente a mesma quantidade de tempo como dizendoif (self == [MyClass class])
na+initialize
. Se você já possui um+initialize
, sim, criar a instância compartilhada é mais rápido, mas a maioria das classes não.Porque ele será executado apenas uma vez. Portanto, se você tentar acessá-lo duas vezes a partir de threads diferentes, isso não causará problemas.
Mike Ash tem uma descrição completa em seu post no blog Care and Feeding of Singletons .
Nem todos os blocos GCD são executados de forma assíncrona.
fonte