Escrito por Reinder de Vries, em 10 de janeiro de 2019 em Desenvolvimento de aplicativos, o Swift
Um singleton é uma classe do que exatamente uma instância existe, que pode ser acessado globalmente. Como você cria um singleton no Swift? E por que você deveria ou não deveria?
neste tutorial, vamos mergulhar em singletons em Swift. Você aprende o que é o padrão de design singleton e por que é útil. Discutiremos a sintaxe para criar singletons no Swift. E vamos entrar em casos de uso bons e ruins para singletons.
pronto? Vamos.
- O Que É Um Singleton?
- Codificando Um Singleton Em Swift
- Quando Usar Singletons
- Leitura Adicional
O Que É Um Singleton?
um singleton é uma classe da qual existe apenas uma instância. Alguns exemplos:
- Uma empresa tem somente um
CEO
- Uma API de classe tem apenas uma série de fila de solicitação de
- Um sistema operacional tem apenas um sistema de arquivos
- Um corpo do sistema solar gira em torno de um ponto gravitacional
- Um aplicativo que faz e/S tem apenas um padrão
FileManager
- Um avião tem apenas um convés de vôo
O segundo atributo de um singleton é que ele tem um ponto global de acesso. Você pode acessar um singleton, por exemplo. funções de chamada nele, de qualquer lugar no código do seu aplicativo.
então, para resumir:
- um singleton é uma classe que tem apenas uma instância
- pode ser acessada globalmente, ou seja, em qualquer lugar do seu código
no desenvolvimento prático do iOS, você usa singletons com frequência. Classes típicas como NotificationCenter
, UserDefaults
, SKPaymentQueue
e FileManager
tem shared
ou default
propriedades que são singletons.
em outros momentos, você pode querer criar um singleton você mesmo. Um bom caso de uso é uma classe API
que expõe a instância singleton por meio de sua propriedade shared
. Você usa API.shared.makeAPICall()
para acessar a API por meio de uma única instância unificada. Isso permite que você, por exemplo, gerencie chamadas de API em série.
antes de discutirmos quando os singletons são melhor usados (e quando não), vamos descobrir como codificar um singleton no Swift.
seja contratado como desenvolvedor iOS
Aprenda a criar aplicativos iOS 14 com Swift 5
Inscreva-se no meu curso de desenvolvimento iOS e aprenda como iniciar sua carreira como desenvolvedor profissional de iOS.
codificando um Singleton em Swift
esta é a melhor maneira de criar um singleton em Swift:
class API{ static let shared = API() private init() { // Set up API instance }}
e veja como você usa o singleton:
API.shared.doSomething()
estamos criando uma classe API
que tem uma propriedade estática chamada shared
. Essa propriedade não pode ser alterada uma vez definida, porque é uma constante e é declarada estaticamente.
isso significa que podemos acessar a propriedade shared
por meio da classe API
. Isso geralmente é chamado de propriedade de classe. Compare isso com uma propriedade de instância normal, que só pode ser acessada por meio de uma instância de uma classe.
o que é interessante é que a propriedade shared
inicializa uma instância de API
dentro da classe API
. Estamos criando um objeto API
que pode ser acessado por meio da classe API
. Mas há mais …
o inicializador de classe init()
está marcado com private
. Esta palavra-chave private
garante que a classe API
só possa ser inicializada dentro da classe API
.
em outras palavras, você não pode criar uma instância de API
fora da classe API
! Isso garante que o objeto API
que criamos seja a única instância em nosso código. Afinal, você não pode criar mais disso.
e agora garantimos que a classe API
está em conformidade com os dois atributos de um singleton:
- Graças à propriedade estática
shared
, oAPI
instância pode ser acessado globalmente - Graças a
private init()
, oAPI
classe não pode ser inicializado fora doAPI
classe
Isso tudo pode parecer um pouco abstrato para você, então vamos expandir o exemplo anterior, com um pouco mais de código prático. Aqui está o que:
a classe API
é principalmente a mesma. Ainda é um singleton e ainda usa esses bits de código static let shared = API()
e private init()
.
aqui está o que mudou:
- a classe
API
agora tem uma propriedadeisRequestPending
. É aqui que o perigo começa… veja como o booleanoisRequestPending
garante que apenas uma solicitação de API possa ser feita de cada vez? (Observe queisRequestPending
é uma propriedade de instância.) - a classe
API
também tem uma funçãomakeAPIRequest()
. Imagine que podemos usar essa função para recuperar alguns dados de uma API de webservice, como a do Twitter. na função, você pode ver que uma solicitação só pode ser feita quando nenhuma outra solicitação estiver pendente no momento. - a classe
API
também tem uma funçãoonReturnAPIRequest()
. Esta função é invocada quando a solicitação da API retorna, ou seja, os dados on-line foram baixados para o aplicativo. O booleanoisRequestPending
é definido comofalse
novamente e os dados da solicitação são processados.
e veja como podemos usar o singleton API
em qualquer lugar em nosso código:
API.shared.makeAPIRequest()
há outra coisa que precisamos discutir. A classe API
agora gerencia algo chamado state. Você pode ver “Estado” como um sentimento: você é feliz ou está triste, ou está com raiva, e assim por diante. Você pode mudar de um estado para o outro.
a classe API
pode alternar entre dois estados:
- Um estado em que
isRequestPending
éfalse
- Um estado em que
isRequestPending
étrue
Como você aprenderá na próxima seção, estado e singletons pode causar todos os tipos de estragos no seu código. Gerenciar o estado mal é a maior razão para o uso indevido de singleton.
quando usar Singletons
quando você usa singletons? O livro Design Patterns: Elements of Reusable Object-Oriented Software by the Gang of Four tem o seguinte a dizer. Use o padrão singleton quando:
- deve haver exatamente uma instância de uma classe, e deve ser acessível a clientes de um conhecido ponto de acesso
- quando a única instância deve ser extensível por subclasses, e os clientes devem ser capazes de usar um longo instância, sem modificar o código
isso é complicado, mas o que ferve para baixo é:
- Usar um singleton quando o código não requer mais do que uma instância de uma classe (por exemplo, o CEO da empresa)
- E quando ele deve ser acessível a partir de qualquer lugar no seu código (i.e., o sistema de arquivos)
outro caso de uso é a subclassificação. Uma variável global em seu código não pode ser facilmente subclassificada, então é por isso que você usa uma classe singleton. Além disso, os singletons podem ser testados por unidade usando injeção de dependência. Você substitui a instância API
por uma instância APIMock
e obtém a capacidade de acionar chamadas de API de teste sem fazer as solicitações de rede reais.
e quando você não usa singletons? Para responder a essa pergunta, teremos que voltar ao princípio do Estado que discutimos anteriormente.
uma armadilha comum para Desenvolvedores iOS iniciantes é gerenciar o estado e suas dependências mal. Imagine que você está construindo um aplicativo que usa a classe API
com a qual trabalhamos anteriormente.
toda vez que você expande a classe API, você usa cada vez mais propriedades, como:
- Um
userID
propriedade que mantém o controle do usuário em sessão, uma vez que ologin()
chamada de API foi feita - Um
tweets
propriedade com o Twitter de dados, uma vez que ogetTweets()
chamada foi feita - Um
spinner
propriedadeUIActivityIndicatorView
que você adicionar a um controlador de visualização quando uma solicitação começou
Em primeiro lugar, isso faz muito sentido. Afinal, a classe API
pode ser acessada em qualquer lugar do seu código. Portanto, no controlador Tweet View, você pode usar a matriz API.shared.tweets
e, no controlador de Configurações, pode usar userID
para informar rapidamente à API cujas configurações devem ser alteradas.
infelizmente, seu estado está agora em todo o lugar. A classe API
tem dependências para um monte de classes que não estão relacionadas à responsabilidade única da classe API. Seu código se tornou uma tigela de espaguete, tudo emaranhado. O código pode funcionar bem, mas é impossível manter e estender.
vejamos um exemplo. O onReturnAPIRequest()
função é definida anteriormente está à beira de se tornar fortemente acoplado…
Aqui está o que nós estamos considerando:
- O
onReturnAPIRequest()
é chamado quando uma API webservice solicitação retorna, i.e. quando vem os dados para o aplicativo. Esses dados precisam ir a algum lugar – um controlador de visualização de Tweet, por exemplo. Como você passa os dados doAPI
para o controlador de visualização? - uma escolha óbvia é apenas criar uma referência ao
viewController
na classeAPI
. Quando os dados entram, você pode codificar algo comoviewController.tweets = tweetsData
. Esta é uma arquitetura ruim, infelizmente, porque agora oAPI
e o controlador de visualização estão fortemente acoplados. É impossível (ou difícil) testar a unidade e provavelmente criará problemas ao estender qualquer classe. - é melhor escolher um mecanismo que não combine firmemente as duas classes. Uma opção seria passar um encerramento para
onReturnAPIRequest()
, que é executado quando a solicitação retorna. Esse fechamento pode então conter código para lidar com os dados recebidos. Outra opção seria usarNotificationCenter
para passar os dados para o controlador de visualização ou usar uma classeDatabase
para lidar com os dados.
o padrão de design singleton ganhou alguma controvérsia, simplesmente porque é fácil usar mal. Ao usar singletons, esteja atento ao estado e às dependências. Só porque é fácil ter acesso global ao Estado, isso não significa que seja uma boa ideia.
seja contratado como desenvolvedor iOS
Aprenda a criar aplicativos iOS 14 com Swift 5
Inscreva-se no meu curso de desenvolvimento iOS e aprenda como iniciar sua carreira como desenvolvedor profissional de iOS.
Leitura Adicional
e isso é tudo o que há para isso! Conhecer singletons é um objetivo que vale a pena, especialmente se você estiver interessado em arquitetura de aplicativos e design de sistemas.