1. Início
  2. Mobile
  3. O que mudou no Swift 5?

O que mudou no Swift 5?

fundo roxo com logo da linguagem swift e da geekhunter

Olá. Nessa matéria você irá encontrar algumas das novidades da mais recente versão (lançada em Março de 2019) da linguagem Swift, o Swift 5, utilizada para o desenvolvimento de aplicações para os dispositivos da Apple.

O conteúdo explica detalhadamente alguns dos principais recursos introduzidos e também apresenta alguns trechos de código, para tornar o aprendizado bem prático.

Para executar os códigos apresentados é necessário ter o Xcode a partir da versão 10.2, que suporta o Swift 5.

Também é possível baixar o playground disponível aqui, que possui todos os trechos de códigos apresentados.

Interoperabilidade no Swift 5

fundo roxo com logo da linguagem swift 5 e da geekhunter

O Swift 5 traz para a linguagem alguns recursos importantes que possibilitam a interoperabilidade entre as aplicações, bibliotecas e sistemas operacionais com suporte a diferentes versões da linguagem.

Esses recursos são de extrema importância e demonstram uma grande evolução da linguagem, fazendo com que ela se estabeleça ainda mais fortemente no mercado.

Eles são semelhantes entre si, mas cada um permite uma coisa um pouco diferente da outra. Veja a seguir uma explicação mais aprofundada sobre cada um deles.

>>Leitura Recomendada:
Um guia para o programador iniciante

ABI – Application Binary Interface

Essa tecnologia, declarada estável a partir da nova versão de número 5, faz com que todos os sistemas operacionais da Apple possuam a biblioteca padrão da linguagem.

Isso faz com que as aplicações criadas fiquem menores, porque a biblioteca padrão não precisa mais estar nas aplicações.

E permite interoperabilidade entre as aplicações que foram desenvolvidas com o Swift 5 e os sistemas operacionais que possuem suporte à versão e às versões posteriores da linguagem que forem lançadas.

Exemplo do que o ABI possibilita. Uma aplicação desenvolvida com o Swift 5 irá funcionar tanto em uma máquina que tenha suporte a mesma versão, quanto em máquinas que tenham suporte a hipotéticas versões superiores a 5. 

Module Stability

Essa tecnologia permite a interoperabilidade entre frameworks e aplicações, independente da versão do Swift com a qual ambos foram desenvolvidos.

Isso faz com que seja desnecessário garantir que a aplicação e as suas bibliotecas sejam desenvolvidas com a mesma versão do Swift (isso a partir da versão 5).

Essa tecnologia trabalha em conjunto com a ABI, e ainda não está totalmente estável.

grafico
Exemplo do que o Module Stability possibilita. Um framework que foi desenvolvido com uma suposta versão 6 da linguagem funciona tanto com a versão 6 quanto com uma hipotética versão 7 ou superior. 

Library Evolution

Essa tecnologia faz com que seja desnecessário recompilar uma aplicação quando alguma das bibliotecas padrão do Swift forem atualizadas. Ela também ainda não está totalmente estável.

Exemplo do que a Library Evolution possibilita. Uma aplicação que utiliza uma versão de alguma biblioteca padrão do Swift irá funcionar tanto em máquinas cujo sistema operacional dê suporte a mesma versão dessa biblioteca, quanto em máquinas cujo sistema operacional dê suporte a versões posteriores dessa mesma biblioteca. 

A imagem a seguir apresenta um resumo sobre as tecnologias apresentadas:

tabela
Como é possível ver, somente a ABI encontra-se estável, enquanto as outras duas ainda estão em desenvolvimento, e talvez demore algumas novas versões até que elas estejam 100% funcionais. 

Swift 5

fundo roxo com logo da linguagem swift 5 e da geekhunter

Nessa seção serão apresentados alguns dos principais recursos que foram introduzidos à linguagem, o que impacta diretamente a vida dos desenvolvedores e das aplicações desenvolvidas com suas versões anteriores.

Casos Futuros de Enum

Assim como outras linguagens, Swift possui uma estrutura chamada enum.

Um enum é uma estrutura que permite definir uma lista de valores (enum vem de enumeration – enumeração).

Ele também pode possuir propriedades, funções, métodos e construtores.

A seguir é apresentado a declaração do enum Categoria.

Ele poderia ser utilizado, por exemplo, como propriedade de uma entidade produto, ou mesmo ser passado como parâmetro de uma função para se executar uma ação específica de acordo com o seu valor. 

Uma prática muito comum quando trabalhando com enum é utilizar um swtich case para executar diferentes ações para cada possibilidade do valor do enum, como apresentado a seguir:

No trecho de código acima, é definida uma variável do tipo do enum Categoria e um valor é atribuído a ela.

Em seguida é executada uma instrução swtich case, que executa ações específicas para dois casos do enum e uma ação genérica para qualquer outro caso. 

Esse é um exemplo muito simples, mas para o problema que quero mostrar é importante ter em mente que em aplicações maiores e mais complexas pode-se encontrar facilmente um enum, que é utilizado em diversas partes do projeto.

Tendo isso em vista, imagine o seguinte cenário: por algum motivo será necessário adicionar um novo valor ao enum, para a categoria adulto, e executar uma ação específica para esse novo valor.

O problema que surge é encontrar todos os casos em que o enum é utilizado em um switch case para acrescentar a nova tratativa. 

Para solucionar esse problema o Swift 5 introduz a notação @unknown default para o switch case.

O notação @unknown default: permite que o switch case possua uma ação genérica.

Mas, caso ele não contemple todos os casos possíveis de valores do enum, é exibido um alert no código, tornando mais fácil encontrar os casos em que o enum foi usado em um switch case quando um novo valor for inserido, facilitando a manutenção do projeto. 

Aviso exibido no Xcode devido ao uso da notação @unknown default:, que torna a manutenção do código mais fácil em grandes projetos.

Nova Função isMultiple(of:)

Antes da versão 5, para se verificar se um número A é múltiplo de outro número B era necessário ver se o resto da divisão de A por B é igual a zero – isso continua funcionando.

Com o Swift 5, todo número inteiro possui a função isMultiple(of:), que recebe outro número inteiro e retorna true ou false para o caso de ser ou não múltiplo. 

Novas Propriedades: isNumber e isAlphabetic

Nessa nova versão é possível identificar se um caractere é um número, através da propriedade isNumber, bem como verificar se os caracteres de uma String são letras, através da propriedade isAlphabetic na representação Unicode de cada caractere. 

Essas duas novas propriedades podem ser muito úteis quando trabalhando com validação de valores textuais digitados pelo usuário e que devem estar em algum formato específico. 

Tratativa de Optionals Aninhados

Uma das grandes preocupações da linguagem Swift é possibilitar a construção de códigos seguros – códigos que não possuam erro.

Pensando nisso, a linguagem adota o conceito de Optional, que nada mais do que um tipo de dado que pode ser nulo.

A utilização desse recurso, combinada com estruturas como if let e guard let, possibilitam evitar a ocorrência de erros ao se tentar acessar o valor de uma variável que não possui valor.  

Veja a seguir um exemplo de utilização de Optional e da estrutura if let.

Outro mecanismo que também possibilita a construção de códigos mais seguros é a estrutura do try catch, disponibilizada pela linguagem Swift para tratar erros que podem vir a ocorrer como resultado da execução de algum trecho de código.

Veja a seguir um exemplo de utilização da estrutura do try catch.

O trecho de código acima está fazendo o seguinte:  

1.

Declara um enum do tipo Error que possui um caso de erro.

2.

Declara a função divedeIfPossible(_: _:) throws -> Double?.

Essa função divide somente valores positivos. Caso algum dos valores seja negativo é retornado nil, caso o segundo parâmetro seja zero é retornado o erro do enum declarado anteriormente, e caso ambos os valores sejam positivos e não nulos é retornado o resultado da divisão.

Sim, essa função é esdrúxula,  mas ela será muito útil para ilustrar esse tópico e te fazer entender a conclusão dessa seção.  

3.

Executa-se a chamada da função dentro de um bloco do com utilização do termo try antes da chamada da função, e um bloco catch caso a função retorne o erro de divisão por zero.

Nesse caso, como o segundo parâmetro foi passado como zero, a função irá retornar o erro, que será impresso na tela ao passar pela tratativa no bloco catch.

Aqui, também é importante notar que é utilizado a estrutura if let para desempacotar o valor Optional que será retornado da função criada em caso de sucesso.  

O Swift possui uma versão resumida da estrutura do try catch que torna possível executar a mesma coisa que foi executada no passo 3 do exemplo anterior em uma única linha. É a notação try?.

Veja o exemplo de utilização seguido da explicação:

O trecho de código usa a notação try? antes da chamada da função divedeIfPossible(_: _:) throws -> Double?, que pode retornar um erro.

Essa instrução faz com que a função seja executada e, caso seja retornado um erro, ele será transformado em um tipo Double?, contendo o valor nil; e caso retorne um valor, ele também é encapsulado em um Optional, contendo o valor retornado pela função. 

Enfim chegamos ao nosso problema: devido ao fato de a nossa função retornar um valor Optional e a instrução try? também tentar encapsular o valor retornando da função dentro de outro Optional ao fim da execução do trecho de código acima acabaríamos com um retorno do tipo Double?? (um Double duplamente Optional).

Isso é ruim porque dá mais trabalho para o desenvolvedor, fazendo com que seja necessário desempacotar o valor duas vezes.

Com o Swift 5 isso não acontece mais, e em casos como esse o valor retornado será do tipo Double? (somente um Optional). Veja as imagens a seguir que ilustram o problema.

codigos de programacao
Utilização da instrução try? com a função divedIfPossible criada anteriormente no Swift 4.2. O tipo do valor retornado é Double??
codigos de programacao
Desempacotamento do valor retornado no Swift 4.2.
codigos de programacao
Utilização da instrução try? com a função divedIfPossible criada anteriormente no Swift 5.0. O tipo do valor retornado é Double?

Nova Função compactMapValues()

O Swift 5 traz uma nova função nativa para dicionários, a compactMapValues, que possibilita mudar o tipo dos valores de um dicionário e remover os pares cujo os valores são nil.

Isso é feito através de uma Closure que deve ser passado como parâmetro da função.

A Closure deve retornar um valor Optional do novo tipo de dados para o qual os valores do dicionário serão transformados.

Sempre que essa Closure retornar um valor nil o par chave/valor correspondente é eliminado no novo dicionário.

No exemplo acima temos um dicionário de alunos e suas notas do tipo [String:String] (isso quer dizer que suas chaves e os seus valores são Strings).

Ele poderia ser o resultado obtido pela chamada de uma API, por exemplo.

Entretanto, seria muito complicado trabalhar com as notas dos alunos no formato de texto.

Com isso, a função compactMapValues é utilizada no dicionário para transformar as notas em valores inteiros e remover os alunos que ainda não possuem nota, facilitando a manipulação da estrutura. 

A implementação da Closure tenta transformar o valor recebido em um inteiro, para então retorná-lo, e caso não consiga, retorna nil.

Essa implementação poderia ser simplificada, possibilitando executar a mesma filtragem de maneira muito mais elegante.

Raw Strings

Em Swift, assim como em grande parte das linguagens de programação, os valores do tipo texto são criados com a utilização das aspas duplas (abre-se aspas duplas, coloca-se o texto desejado, fecha-se aspas duplas).

Há casos em que é necessário utilizar alguns caracteres especiais em uma String. Por exemplo, quando se quer colocar uma aspa dupla como parte da String.

Para isso, é necessário adicionar um valor de escape antes do caractere (uma barra invertida). 

Com as Raw Strings é desnecessário a utilização dessa barra invertida, tornando a construção da String muito mais simplificada.

Para isso, basta adicionar uma hashtag antes e após as aspas que abrem e fecham a String.

Para se utilizar o caractere hashtag dentro da String, coloca-se duas hashtags antes e após as aspas que abrem e fecham a String.

E, para a interpolação de valores em uma Raw String, deve-se adicionar uma barra invertida, a mesma quantidade de hashtags utilizada antes e após as aspas que abrem e fecham a string, e o valor que se quer concatenar entre parênteses.

Também é possível construir Raw Strings de múltiplas linhas (Strings de múltiplas linhas não são novidades do Swift 5).

Um grande exemplo de utilização das Raw Strings é na construção de regex. 

Dynamically Callable Types

Esse novo recurso da linguagem foi pensado para facilitar a sua utilização em conjunto com outras linguagens como JavaScript e Python.

Ele permite, basicamente, utilizar um objeto como se fosse uma função, com passagem ilimitada de parâmetros e diferentes tipos de dado como retorno.

Veja a seguir um exemplo de utilização:

O trecho de código acima está fazendo o seguinte:

1.

Declara a classe CalculatorOfOneOperation (calculadora de uma operação – novamente um componente que muito dificilmente será utilizado em um cenário real, mas que será muito útil para a explicação do recurso), que possui um atributo – uma Closure que recebe dois valores do tipo Double e também retorna um valor do tipo Double.

Esse argumento representa qual o tipo de operação realizada pelo objeto instanciado a partir da classe, e deve ser passado para o seu construtor.

A notação @dynamicCallable serve para dizer que a classe criada é um tipo dinâmico que pode gerar objetos que podem ser utilizados como funções, permitindo a configuração da classe para que isso ocorra.

2 e 3.

Declara as funções que são chamadas quando o objeto criado a partir da classe CalculatorOfOneOperation é utilizado como uma função.

Suas implementações são iguais, e utilizam a Closure passada no construtor do objeto para executar a operação definida em todos os valores que forem passados como argumentos durante a chamada.

A diferença é que para utilizar a primeira é necessário dar nome aos argumentos (definir os labels) na hora da chamada, enquanto que na segunda não.

 4.

É instanciado um objeto que permite a realização de somas. 

5.

Utiliza o objeto criado no passo anterior como se fosse uma função.

Os valores passados como argumento serão transformados no vetor [ 1, 2, 3, 4, 5 ], que será passado como valor do argumento args da função definida no item 3. 

6.

Utiliza o objeto criado no passo anterior como se fosse uma função, nomeando os parâmetros da chamada.

Os valores passados como argumento serão transformados no dicionário [ “arg1” : 1, “arg2” : 2, “arg3 “: 3, “arg4” : 4, “arg5” : 5 ], que será passado como valor do argumento args da função definida no item 2.

>>Leitura Recomendada:
Flutter: introdução ao framework da Google 

Conclusão

fundo roxo com logo da linguagem swift e da geekhunter

A cada nova versão da linguagem Swift, novos recursos importantes são adicionados, como é o caso da versão 5, que traz para os desenvolvedores novos recursos que facilitam o seu trabalho.  

Essa matéria apresentou apenas alguns dos principais recursos novos que foram introduzidos. Mais novidades e todos os recursos podem ser encontrados nas documentações e blogs oficiais da linguagem.

Crie um perfil na GeekHunter e receba propostas alinhadas ao seu perfil. São mais de 1000 vagas abertas, inclusive Vagas Swift (iOS) e Vagas Swift (MacOS).

Categorias

Leituras Recomendadas

Quer receber conteúdos incríveis como esses?

Assine nossa newsletter para ficar por dentro de todas as novidades do universo de TI e carreiras tech.