
O Swift 5.0 tornou-se disponível com o lançamento do Xcode 10.2, mas o trabalho na próxima versão continua e já existem notícias do que você pode esperar nela.
Um recurso importante do
Swift 5.1 é a
estabilidade do módulo , o que nos permite usar bibliotecas de terceiros sem nos preocuparmos com qual versão do compilador Swift eles foram criados. Parece com a
estabilidade ABI que obtivemos no Swift 5.0, mas há uma pequena diferença: a estabilidade ABI resolve diferenças nas versões Swift em tempo de execução e estabilidade do módulo em tempo de compilação.
Além dessa inovação importante, receberemos várias melhorias importantes no Swift e, neste artigo, as examinaremos com exemplos para que você possa vê-las em ação.
Auto Universal
SE-0068 estende o uso de
Self , para que ele se refira ao tipo que o contém em classes, estruturas e enumerações. Isso geralmente é útil para tipos dinâmicos quando é necessário determinar o tipo exato de algo em tempo de execução.
Como exemplo, considere o seguinte código:
class NetworkManager { class var maximumActiveRequests: Int { return 4 } func printDebugData() { print("Maximum network requests: \(NetworkManager.maximumActiveRequests).") } }
Aqui, definimos a propriedade estática
maximumActiveRequests dentro da classe
NetworkManager e adicionamos o método
printDebugData () para imprimir essa propriedade. Está tudo bem aqui, mas apenas até decidirmos herdar do
NetworkManager :
class ThrottledNetworkManager: NetworkManager { override class var maximumActiveRequests: Int { return 1 } }
Nesse herdeiro, alteramos a propriedade maximumActiveRequests para que agora seja igual a um, mas se chamarmos
printDebugData () , ele
inferirá o valor da classe pai:
let manager = ThrottledNetworkManager() manager.printDebugData()
Aqui devemos obter 1 em vez de 4, e aqui vem o resgate SE-0068: podemos usar
Self (com o capital 'S') para se referir ao tipo atual. Portanto, agora podemos reescrever o método
printDebugData () da classe pai como este:
class ImprovedNetworkManager { class var maximumActiveRequests: Int { return 4 } func printDebugData() { print("Maximum network requests: \(Self.maximumActiveRequests).") } }
Ou seja, o
Self funciona da mesma maneira que trabalhou em protocolos nas versões anteriores do Swift.
Avisos de ambiguidade nenhum
Os opcionais no Swift são implementados como uma enumeração com duas opções:
alguma e
nenhuma . Isso pode causar confusão se criarmos nossa própria enumeração que tem uma opção
none e a incluiremos em
opcional . Por exemplo:
enum BorderStyle { case none case solid(thickness: Int) }
Ao usar não opcional, tudo fica limpo:
let border1: BorderStyle = .none print(border1)
Isso resultará em "nenhum". Mas se usarmos opcional para essa enumeração, encontraremos um problema:
let border2: BorderStyle? = .none print(border2)
Nada será impresso aqui, pois Swift acredita que .none significa opcional está
vazio , embora seja realmente opcional
com o valor BorderStyle.none.
No Swift 5.1, em caso de tal ambiguidade, um aviso será exibido:
“Supondo que você queira dizer 'Opcional.nenhum'; você quis dizer 'BorderStyle.none'? ”
Assim, o desenvolvedor será informado de que, com seu código, nem tudo pode ser tranquilo.
Correspondência de enumerações opcionais e não opcionais
Swift é inteligente o suficiente para entender a construção switch / case ao combinar valores opcionais / não opcionais de texto e números inteiros, mas não no caso de enumerações.
Agora, no Swift 5.1, podemos usar switch / case para corresponder às opções opcionais e não opcionais de enumeração:
enum BuildStatus { case starting case inProgress case complete } let status: BuildStatus? = .inProgress switch status { case .inProgress: print("Build is starting…") case .complete: print("Build is complete!") default: print("Some other build status") }
O Swift é capaz de mapear enumerações opcionais para opções não opcionais, e “Compilação está iniciando ...” será exibido aqui.
Comparar coleções ordenadas
O SE-0240 introduziu a capacidade de calcular diferenças entre coleções ordenadas, além de aplicar o resultado da comparação resultante às coleções. Isso pode ser de interesse para desenvolvedores que possuem coleções complexas em uma visualização de tabela e precisam adicionar ou remover muitos elementos usando animação.
O princípio básico é simples - o Swift 5.1 fornece uma nova
diferença de método
(de :) , que determina as diferenças entre duas coleções ordenadas - quais elementos adicionar e quais remover. Isso se aplica a qualquer coleção solicitada que contenha itens que estejam em conformidade com o protocolo
Equatable .
Para demonstrar isso, criaremos duas matrizes de valores, calcularemos as diferenças de uma das outras e, em seguida, examinaremos a lista de diferenças e as aplicaremos para tornar as duas coleções iguais.
Nota: como o Swift agora está distribuído como parte dos sistemas operacionais da Apple, novas ferramentas de idioma devem ser usadas com a verificação
#available para garantir que o código seja executado em um sistema operacional compatível com a funcionalidade necessária. Para funcionalidades em execução em sistemas operacionais desconhecidos e sem aviso prévio que podem ser lançados no futuro, é usado um número de versão especial, "9999", que significa: "Ainda não sabemos o número da versão correta".
var scores1 = [100, 91, 95, 98, 100] let scores2 = [100, 98, 95, 91, 100] if #available(iOS 9999, *) { let diff = scores2.difference(from: scores1) for change in diff { switch change { case .remove(let offset, _, _): scores1.remove(at: offset) case .insert(let offset, let element, _): scores1.insert(element, at: offset) } } print(scores1) }
Para uma animação mais avançada, podemos usar o terceiro parâmetro na lista resultante de diferenças:
AssociatedWith . Assim, em vez de
.insert (deixe deslocamento, deixe elemento, _), podemos escrever .insert (deixe deslocamento, deixe elemento,
deixe associado a ). Isso nos permite rastrear simultaneamente pares de alterações: mover o elemento na coleção duas posições para baixo está excluindo o elemento e, em seguida, adicionando-o, e
associado. Com "vincula" essas duas alterações e permite que você considere esse movimento.
Em vez de aplicar as diferenças manualmente, uma a uma, você pode aplicá-las de uma só vez usando o novo método apply
() :
if #available(iOS 9999, *) { let diff = scores2.difference(from: scores1) let result = scores1.applying(diff) ?? [] }
Criando matrizes não inicializadas
O SE-0245 introduziu um novo inicializador para matrizes que não o preenche com valores padrão. Ele estava disponível anteriormente como uma API privada, o que significava que o Xcode não solicitava a conclusão do código, mas você poderia usá-lo se necessário e entendeu o risco de que essa funcionalidade possa não estar no futuro.
Para usar o inicializador, defina o tamanho da matriz e passe o fechamento que preenche a matriz com valores. Um fechamento receberá um ponteiro inseguro para um buffer mutável, bem como um segundo parâmetro no qual você indica quantos valores realmente usa.
Por exemplo, podemos criar uma matriz de 10 números inteiros aleatórios como este:
let randomNumbers = Array<Int>(_unsafeUninitializedCapacity: 10) { buffer, initializedCount in for x in 0..<10 { buffer[x] = Int.random(in: 0...10) } initializedCount = 10 }
Existem várias regras:
- Você não precisa usar todo o volume solicitado, mas não pode excedê-lo. Ou seja, se você definir o tamanho da matriz como 10, poderá definir initializedCount no intervalo de 0 a 10, mas não 11.
- se você não inicializou os elementos usados na matriz, por exemplo, você definiu initializedCount como 5, mas não forneceu valores reais aos elementos de 0 a 4, provavelmente eles receberão valores aleatórios. Como você sabe, esta é uma má opção.
- Se você não definir initializedCount , será igual a 0 e todos os dados que você atribuiu serão perdidos.
Sim, podemos reescrever o código usando
map () :
let randomNumbers2 = (0...9).map { _ in Int.random(in: 0...10) }
Isso é obviamente mais legível, mas não tão eficaz: criamos um intervalo, depois um novo array vazio, atribuímos um tamanho e "percorremos" o intervalo inteiro, aplicando um fechamento a cada elemento.
Conclusão
O Swift 5.1 ainda está em desenvolvimento e, embora a ramificação final do próprio Swift tenha passado, as alterações de alguns outros projetos relacionados ainda são visíveis.
Portanto, a mudança mais importante é a
estabilidade do módulo e sabe-se que a equipe de desenvolvimento está trabalhando duro nisso. Eles não deram uma data exata de lançamento, embora tenham dito que o Swift 5.1 teve um tempo de desenvolvimento significativamente menor em comparação com o Swift 5.0, que exigia uma concentração extraordinária de energia e atenção. Podemos assumir o acesso ao WWDC19, mas é óbvio que esse não é o caso quando você precisa se apressar para uma determinada data.
Outro ponto que merece atenção. Duas mudanças nesta lista (“Avisos em caso de ambiguidade da opção nenhum” e “Combinando enumerações opcionais e não opcionais”) não foram o resultado da evolução do Swift, mas foram reconhecidas como bugs e ajustadas.