Preparação de entrevista para iOS 5 - Singletons

May 04 2023
O padrão singleton é um padrão de design que garante que uma classe tenha apenas uma instância e fornece um ponto de acesso global a essa instância. Isso pode ser útil quando uma classe precisa ser compartilhada em várias partes de um aplicativo, mas não é prático ou desejável criar várias instâncias da classe.

O padrão singleton é um padrão de design que garante que uma classe tenha apenas uma instância e fornece um ponto de acesso global a essa instância. Isso pode ser útil quando uma classe precisa ser compartilhada em várias partes de um aplicativo, mas não é prático ou desejável criar várias instâncias da classe. No iOS, o padrão singleton é um padrão de design comumente usado.

Questões de entrevista

  • O que é Singleton e como ele é usado no desenvolvimento iOS?
  • Você pode explicar o padrão de projeto Singleton e suas vantagens?
  • Quais são as possíveis maneiras de evitar várias instâncias de Singleton em um ambiente multithread?
  • Você pode dar um exemplo de quando você usaria Singleton em seu aplicativo iOS?
  • Como você testa o Singleton no iOS?

Uma preocupação frequente com singletons é que muitas vezes eles não são thread-safe. Eles são frequentemente usados ​​a partir de vários controladores que acessam a instância singleton simultaneamente.

Você precisa considerar duas coisas ao criar um singleton

  • A instância deve ser criada de maneira thread-safe
  • Você deve marcar o método init da classe como privado para evitar a criação de mais instâncias
  • Durante a inicialização da instância singleton.
  • Durante leituras e gravações na instância.

Para implementar o padrão singleton no Swift, a classe que precisa ser um singleton é definida com a staticpalavra-chave, que indica que a classe possui apenas uma instância. Uma variável estática é usada para armazenar a instância da classe e um método estático é usado para acessar a instância. Aqui está um exemplo de uma classe singleton em Swift

class Singleton {
		// Swift guarantees initialization is atomic
		// Swift treats the code performing initialization as a critical section
    static let shared = Singleton()
    
    // prevents the creation of additional instances of the class.
    private init() {}
}

let singleton = Singleton.shared

@implementation MySingleton

// Lazy initializer 
+ (instancetype)sharedInstance {
    static dispatch_once_t once;
    static id sharedInstance;
  // The token ensures that init is executed only once in thread safety manner
    dispatch_once(&once, ^{
        _sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}
// Prevent creating new instance of the singleton
- (instancetype)init __attribute__((unavailable("Use +[MyClass sharedInstance] instead")));
+ (instancetype)new __attribute__((unavailable("Use +[MyClass sharedInstance] instead")));
@end

Prós

  • Garante que apenas uma única instância de uma classe seja criada, o que pode ajudar a economizar memória e melhorar o desempenho.
  • Fornece um ponto de acesso global à instância da classe, o que pode facilitar o uso em seu código.
  • Pode ser útil para implementar recursos compartilhados, como bancos de dados ou conexões de rede, que precisam ser compartilhados entre diferentes partes do seu código.
  • Pode dificultar o teste e a depuração do seu código, pois introduz um estado global que é compartilhado entre diferentes partes do seu código.
  • Torna difícil criar várias instâncias de uma classe para teste ou outros fins.
  • Pode levar a um acoplamento rígido e violar os princípios do design orientado a objetos.
  • Não é uma boa opção para nenhuma tarefa relacionada à sessão do usuário, pois pode ser necessário destruir e criar um novo singleton quando o usuário fizer logout.

Há uma garantia de 1 por conta (em vez de uma garantia de um por aplicativo). O acesso não é global (você precisa de uma sessão de usuário). Semelhante ao singleton, criado preguiçosamente no primeiro acesso, a mesma instância é sempre retornada posteriormente. Por exemplo MyUserSession, é criado quando um usuário autenticado inicia uma sessão. Deve ser injetado em qualquer código que contenha dados do usuário