Swift 101: Desmistificando os inicializadores de Swift (Parte 1)

Agora que a Apple lançou oficialmente o Xcode 6 e o ​​NDA foi levantado, é hora de mergulhar mais fundo no Swift - a nova linguagem da Apple para criar aplicativos iOS. Aprender a usar inicializadores corretamente no Swift pode ser assustador no começo. A exigência do Swift de que todas as propriedades armazenadas em uma classe sejam inicializadas adiciona complexidade ao processo de inicialização. Na primeira parte deste post de duas partes, vou desmistificar os inicializadores enquanto forneço uma abordagem prática para aprender a melhor implementar inicializadores em suas classes personalizadas.



Quando você cria suas próprias classes personalizadas no Swift, você precisa ter certeza de que os novos objetos instanciados de sua classe personalizada estão inicializados corretamente (prontos para serem usados). outra configuração especializada que sua classe possa exigir.

No Swift, todas as propriedades armazenadas devem ser inicializadas. Eles não estão autorizados a estar em um estado desconhecido. Existem duas maneiras principais de armazenar um valor inicial em uma propriedade:

  1. Na declaração de propriedade - Por exemplo:

  1. Em um inicializador - Por exemplo:

Nas situações em que o valor inicial da propriedade é sempre o mesmo, deve-se escolher a primeira opção e inicializar o valor na declaração da propriedade. Isso vincula intimamente a inicialização da propriedade com sua declaração, tornando seu código mais intuitivo.

Nos casos em que o valor inicial de uma propriedade muda, você deve escolher um inicializador.

Inicialização e Inferência de Tipos

Se você armazenar um valor inicial na declaração de uma propriedade, não precisará especificar o tipo da propriedade porque o Swift pode descobrir ou inferir seu tipo com base no tipo do valor que você está armazenando na propriedade.

No entanto, se você definir o valor inicial de uma propriedade em um inicializador, deverá especificar o tipo da propriedade ao declará-la.

Criando inicializadores

Aqui estão algumas das regras básicas que regem os inicializadores:

  • Inicializadores em Swift são sempre nomeados aquecer .
  • Você não usa o função palavra-chave ao declarar um inicializador.
  • Inicializadores não retornam um valor.
  • Você pode criar vários inicializadores para uma única classe que aceite parâmetros diferentes.
  • Se sua classe tiver uma superclasse, você deve chamar um de seus inicializadores designados de seu inicializador personalizado (mais sobre isso daqui a pouco).

Parâmetros do inicializador

Você pode criar vários métodos inicializadores para sua classe personalizada que fornecem aos consumidores de sua classe uma variedade de maneiras de inicializar objetos.

Se você tiver uma classe que exige que propriedades específicas sejam definidas pelo desenvolvedor do aplicativo, você deve absolutamente criar um ou mais inicializadores que permitam que esses valores sejam passados ​​na inicialização. Isso ajuda a tornar sua classe auto-documentada.

Para ajudá-lo a entender melhor como os inicializadores funcionam, vamos criar um Tradutor cujo objetivo é traduzir frases de um idioma para outro (isso será apenas uma maquete.) Primeiro, criaremos a classe sem inicializadores e depois a melhoraremos adicionando um inicializador com parâmetros.

Para seguir estas instruções passo a passo, baixe o InitializerDemo projeto de exemplo de esse link .

  1. Abra o InitializerDemo projeto localizado na pasta onde você o baixou.
  1. Clique com o botão direito do mouse InitializerDemo grupo e selecione Novo arquivo... a partir do menu pop-up.
  1. No lado esquerdo da caixa de diálogo Criar arquivo sob o iOS seção, selecione Fonte .
  1. No lado direito da caixa de diálogo, selecione o Arquivo Swift modelo e, em seguida, clique em Próximo .
  1. Na caixa de diálogo Salvar arquivo, altere o Nome do arquivo para Tradutor.rápido e, em seguida, clique no Crio botão Isso adiciona o Tradutor.rápido arquivo para o projeto.
  1. Adicione a seguinte declaração de enumeração na parte superior do arquivo abaixo do Importar Fundação declaração:

Essa enumeração declara todos os idiomas suportados pela classe Translator.

  1. Agora adicione a seguinte declaração de classe abaixo da declaração de enumeração:

Neste exemplo, o objetivo principal do Tradutor aula é traduzir frases de um idioma para outro. Ele não pode realizar nenhuma tradução sem conhecer os idiomas 'de' e 'para'. No entanto, o fromLanguage e toLanguage propriedades são marcadas como opcionais. Do ponto de vista prático, eles são qualquer coisa mas opcional!

Observação: Você não precisa definir explicitamente as propriedades opcionais como nil, mas eu fiz isso para contornar um bug com o compilador Swift!

  1. Vamos tentar criar uma instância desta classe a partir de um teste de unidade. Para isso, com o Tradutor.rápido arquivo selecionado no Project Navigator, vá para o File Inspector (o primeiro botão à esquerda na barra de ferramentas do Inspector) e selecione o Testes de demonstração do inicializador caixa de seleção como mostrado em figura 1 . Isso torna a classe acessível ao projeto de teste de unidade.
  Selecione a associação de destino
Figura 1 - Selecione a associação de destino InitializerDemoTests
  1. Debaixo de Testes de demonstração do inicializador grupo no Project Navigator, selecione o InitializerDemoTests.swift Arquivo.
  1. Adicione o seguinte método de teste na parte inferior do arquivo de código acima da chave de fechamento da classe:

Este é um design ruim porque exige que o desenvolvedor descubra por si mesmo que o fromLanguage e toLanguage propriedades devem ser definidas antes do Tradutor objeto pode ser usado.

Vamos criar um design melhor.

  1. Volte para o Tradutor classe e remova o ? = zero depois de Linguagem type para indicar que essas propriedades não são opcionais. Depois, altere o inicializador conforme mostrado aqui:

Esta classe agora tem um único inicializador com a partir de e para parâmetros do tipo Linguagem .

  1. Imprensa Comando+B para construir o projeto. Agora você deve ter um erro de compilador. Para ver o que está causando o problema, selecione o InitializerDemoTests.swift arquivo no Project Navigator e você deve ver o erro mostrado em Figura 2 .
  Erro de compilador de argumento ausente
Figura 2 - O erro do compilador 'Missing argument'

O texto completo do erro indica 'Argumento ausente do parâmetro 'de' na chamada'. Por que você está recebendo este erro?

Se você não especificar um inicializador personalizado para uma classe, nos bastidores, o compilador Swift adiciona um inicializador padrão. É por isso que o código no teste de unidade que tenta usar esse inicializador padrão falha.

No nosso exemplo, isso é exatamente o que queremos! Queremos forçar os desenvolvedores a passar os dois Linguagem valores quando eles criam uma instância da classe. Vamos alterar o código para fazer isso agora.

  1. Primeiro, exclua todo o código dentro do tradutor de teste método. Após, adicione o seguinte código:

Quando você digita os parênteses esquerdos, o Code Completion aparece oferecendo a opção mostrada em Figura 3 .

  Conclusão de código para o inicializador personalizado
Figura 3 - Conclusão de código para o inicializador personalizado

Isso deixa bem claro para um desenvolvedor que ele deve especificar os idiomas 'de' e 'para' ao criar uma instância do Tradutor classe.

  1. Com o modelo de conclusão de código exibido (se não estiver visível, pressione escapar para reexibi-lo), pressione aba para mover-se para o a partir de marcador de posição e tipo Língua inglesa . Imprensa aba uma segunda vez para ir para o marcador de posição e digite Idioma. Chinês . Depois, pressione a tecla de seta para a direita para que o Swift preencha automaticamente os parênteses de fechamento para você. Quando terminar, seu código deve ficar assim:

Como você pode ver, o Code Completion insere os nomes dos parâmetros na chamada do método. Isso é obrigatório. Se você deixar de fora esses nomes de parâmetros, receberá um erro do compilador!

Este não é um verdadeiro teste de unidade, mas eu queria que você experimentasse chamar diferentes tipos de inicializadores.

Nomes de parâmetros locais e externos

Os nomes de parâmetros locais e externos funcionam um pouco diferente para inicializadores do que para métodos regulares.

Como um inicializador é sempre chamado aquecer , você não tem o luxo de criar um nome de inicializador que inclua uma descrição do primeiro parâmetro. Por causa disso, o Swift fornece um nome externo automático que é o mesmo que o nome local para cada parâmetro que você declara, como pode ser visto em Figura 3 .

Se você quiser declarar um nome externo diferente do nome local, use a mesma sintaxe dos métodos normais do Swift. Por exemplo, o código a seguir declara um nome externo diferente para o a partir de e para nomes de parâmetros locais:

Neste exemplo, declarar nomes de parâmetros externos altera os nomes dos parâmetros quando você chama o inicializador conforme mostrado em Figura 4 .

  Os novos nomes de parâmetros externos
Figura 4 - Os novos nomes de parâmetros externos em ação

Se você não quiser fornecer um nome externo para um parâmetro, basta inserir um sublinhado antes do nome do parâmetro local.

Inicializadores designados e de conveniência

O Swift oferece suporte a dois tipos principais de inicializadores – inicializadores designados e inicializadores de conveniência. Vamos dar uma olhada em cada um para que você possa aprender a melhor forma de inicializar suas classes personalizadas.

Inicializadores designados

UMA inicializador designado é o inicializador principal para uma classe. Ele inicializa todas as propriedades declaradas na classe e é responsável por chamar um inicializador em sua superclasse (se tiver uma superclasse).

Por exemplo, no Tradutor classe, init:de:para: é o inicializador designado porque inicializa ambas as propriedades declaradas na classe.

Aqui está a sintaxe de um inicializador designado:

Cada classe deve ter pelo menos um inicializador designado. Você pode ter mais de um, mas é mais comum ter apenas um.

Inicializadores de conveniência

UMA inicializador de conveniência é um inicializador de classe secundária que normalmente aceita menos parâmetros do que um inicializador designado, mas então chama o inicializador designado com padrões definidos para alguns dos parâmetros. Inicializadores de conveniência são opcionais, mas geralmente facilitam a instanciação de suas classes.

Aqui está a sintaxe de um inicializador de conveniência:

Vamos criar um inicializador de conveniência para que você possa entender mais claramente como eles funcionam.

  1. No InitializerDemo projeto, selecione o Tradutor.rápido arquivo no Project Navigator.
  1. Adicione o seguinte novo inicializador ao Tradutor classe:

Aqui estão alguns pontos importantes a serem observados:

  • o conveniência palavra-chave é usada para marcar o método como um inicializador de conveniência.
  • O inicializador de conveniência chama o inicializador designado na mesma classe, passando um padrão Língua inglesa value como o primeiro parâmetro e passando por seu próprio toLanguage parâmetro como o segundo parâmetro.
  • O inicializador de conveniência permite instanciar a classe passando apenas um parâmetro para o inicializador. Por exemplo:

  • Quando você instancia uma instância da classe, o Code Completion agora lista ambos os inicializadores, conforme mostrado em Figura 5 .
  Vários inicializadores no Code Completion
Figura 5 - Vários inicializadores no Code Completion

Conclusão

Este post cobre os fundamentos básicos dos inicializadores em Swift, e há muito mais para aprender! No meu próximo post, discutirei os tópicos 'Initializer Chaining', 'Two-Phase Initialization' e 'Initializer Inheritance'. Fique ligado!