Se você pode segmentar o iOS 4.0 ou superior
Usando o GCD, é a melhor maneira de criar singleton no Objective-C (thread safe)?
+ (instancetype)sharedInstance
{
static dispatch_once_t once;
static id sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
instancetype
. A conclusão do código é muito melhor ao usá-lo em vez deid
.Respostas:
Essa é uma maneira perfeitamente aceitável e segura de thread para criar uma instância da sua classe. Tecnicamente, pode não ser um "singleton" (já que só pode haver um desses objetos), mas desde que você use apenas o
[Foo sharedFoo]
método para acessar o objeto, isso é bom o suficiente.fonte
instancetype
instancetype
é apenas uma das muitas extensões de idioma paraObjective-C
, com mais sendo adicionadas a cada nova versão.Conheça, ame.
E tome como exemplo de como prestar atenção aos detalhes de baixo nível pode fornecer insights sobre novas e poderosas maneiras de transformar o Objective-C.
Consulte aqui: instancetype
fonte
MySingleton.h
MySingleton.m
fonte
init
?MySingleton
, por exemplo,MySingleton.m
eu estou chamando[super alloc]
Você pode evitar que a classe seja alocada substituindo o método de atribuição.
fonte
Dave está correto, está perfeitamente bem. Você pode consultar os documentos da Apple sobre a criação de um singleton para obter dicas sobre como implementar alguns dos outros métodos para garantir que apenas um possa ser criado se as classes optarem por NÃO usar o método sharedFoo.
fonte
Se você quer ter certeza de que [[MyClass aloc] init] retorna o mesmo objeto que sharedInstance (não é necessário na minha opinião, mas algumas pessoas querem isso), isso pode ser feito com muita facilidade e segurança usando um segundo dispatch_once:
Isso permite que qualquer combinação de [[MyClass alocado] init] e [MyClass sharedInstance] retorne o mesmo objeto; [MyClass sharedInstance] seria apenas um pouco mais eficiente. Como funciona: [MyClass sharedInstance] chamará [[MyClass shared] init] uma vez. Outro código poderia chamá-lo também, inúmeras vezes. O primeiro chamador a init fará a inicialização "normal" e armazenará o objeto singleton no método init. Quaisquer chamadas posteriores ao init ignorarão completamente o que a alocação retornou e retornará a mesma sharedInstance; o resultado da alocação será desalocado.
O método + sharedInstance funcionará como sempre. Se não for o primeiro chamador a ligar para [[MyClass assign] init], o resultado do init não será o resultado da chamada de alocação, mas tudo bem.
fonte
Você pergunta se esta é a "melhor maneira de criar singleton".
Algumas reflexões:
Primeiro, sim, esta é uma solução segura para threads. Esse
dispatch_once
padrão é a maneira moderna e segura de thread de gerar singletons no Objective-C. Não se preocupe lá.Você perguntou, porém, se essa é a "melhor" maneira de fazer isso. Deve-se reconhecer, porém, que o
instancetype
e[[self alloc] init]
é potencialmente enganoso quando usado em conjunto com singletons.O benefício
instancetype
disso é que é uma maneira inequívoca de declarar que a classe pode ser subclassificada sem recorrer a um tipo deid
, como tivemos que fazer no passado.Mas o
static
método apresenta desafios de subclassificação. E seImageCache
eBlobCache
singletons fossem subclasses de umaCache
superclasse sem implementar seu própriosharedCache
método?Para que isso funcione, você deve garantir que as subclasses implementem seu próprio
sharedInstance
método (ou o que você chamar para sua classe específica).Resumindo, seu original
sharedInstance
parece suportar subclasses, mas não. Se você pretende dar suporte à subclasse, inclua pelo menos a documentação que avisa os desenvolvedores futuros que eles devem substituir esse método.Para melhor interoperabilidade com o Swift, você provavelmente deseja definir isso como uma propriedade, não um método de classe, por exemplo:
Em seguida, você pode prosseguir e escrever um getter para essa propriedade (a implementação usaria o
dispatch_once
padrão sugerido):O benefício disso é que, se um usuário Swift for usá-lo, ele fará algo como:
Observe que não existe
()
, porque nós o implementamos como uma propriedade. A partir do Swift 3, é assim que os singletons são geralmente acessados. Portanto, defini-lo como uma propriedade ajuda a facilitar essa interoperabilidade.Como um aparte, se você observar como a Apple está definindo seus singletons, esse é o padrão que eles adotaram, por exemplo, seu
NSURLSession
singleton é definido da seguinte maneira:Outra consideração muito pequena sobre a interoperabilidade Swift foi o nome do singleton. É melhor se você pode incorporar o nome do tipo em vez de
sharedInstance
. Por exemplo, se a classe eraFoo
, você pode definir a propriedade singleton comosharedFoo
. Ou, se a classe fosseDatabaseManager
, você poderia chamar a propriedadesharedManager
. Os usuários do Swift poderiam fazer:Claramente, se você realmente deseja usar
sharedInstance
, sempre pode declarar o nome Swift, se desejar:Claramente, ao escrever o código Objective-C, não devemos permitir que a interoperabilidade Swift supere outras considerações de design, mas ainda assim, se pudermos escrever código que suporte graciosamente os dois idiomas, é preferível.
Concordo com os outros que apontam que, se você quer que isso seja um verdadeiro singleton onde os desenvolvedores não pode / não deve (acidentalmente) instanciar suas próprias instâncias, o
unavailable
qualificador noinit
enew
é prudente.fonte
Para criar um singleton seguro para threads, faça o seguinte:
e este blog explica singleton muito bem singletons em objc / cacau
fonte
fonte
fonte