Olá, meu nome é Ilya. Sou desenvolvedor iOS do Tinkoff.ru. Neste artigo, darei uma breve visão geral das principais alterações no Swift 5. Essas alterações são descritas nas
notas de versão . Para quem ainda não se familiarizou, seja bem-vindo ao gato!

O tamanho do aplicativo diminuirá!
Os aplicativos escritos no Swift 5 e compilados para iOS 12.2, watchOS 5.2, tvOS 12.2 não incluirão bibliotecas dinâmicas para a biblioteca padrão Swift e o Swift SDK. E isso significa que o tamanho do aplicativo diminuirá, no entanto, não muito. Se você acredita
neste tweet , o tamanho do projeto vazio foi reduzido de 2,4 Mb para 24 Kb. Um bom resultado para aplicativos pequenos, mas para aplicativos grandes não haverá muita diferença.
@dynamicCallable ( SE-0216 )
O atributo
@dynamicCallable permite trabalhar com um objeto como uma função. Esses objetos são chamados de objetos funcionais ou functors (mais detalhes podem ser encontrados
aqui ). Os objetos funcionais estão em C ++, Python, JavaScript e outras linguagens, e no Swift eles foram adicionados para compatibilidade com essas linguagens. O fato é que o Swift agora interage bem com a API C e o Objective-C, e os desenvolvedores de idiomas desejam adicionar interação com linguagens dinâmicas - Python, JavaScript, Ruby e outros.
Para tornar um tipo um functor, você deve adicionar o atributo
@dynamicCallable à sua declaração. Considere um exemplo de uma estrutura
redutora que pode ser usada para adicionar números em uma matriz:
@dynamicCallable struct Reducer { ... }
Então você precisa implementar um ou ambos dos seguintes métodos:
func dynamicallyCall(withArguments: ExpressibleByArrayLiteral) func dynamicallyCall(withKeywordArguments: ExpressibleByDictionaryLiteral)
A primeira função permite acessar o objeto passando uma matriz como argumentos. A segunda função permite acessar o objeto, passando a mesma matriz que os argumentos, mas usando os nomes dos argumentos.
Por exemplo, uma implementação da primeira função para uma estrutura
Redutora ficaria assim:
func dynamicallyCall(withArguments arguments: [Int]) -> Int { return arguments.reduce(0, +) }
Em seguida, aplique uma estrutura da seguinte maneira:
let reducer = Reducer() let sum = reducer(1, 2, 3)
Consideraremos a implementação do segundo método usando o exemplo da estrutura
Comparator , com a qual podemos comparar dois números:
@dynamicCallable struct Comparator { func dynamicallyCall(withKeywordArguments arguments: KeValuePairs<String, Int>) -> ComparisonResult { guard let lhs = arguments["lhs"], let rhs = arguments["rhs"], lhs != rhs else { return .orderedSame } return lhs > rhs ? .orderedDescending : .orderedAscending } }
Você pode usar essa estrutura da seguinte maneira:
let comparator = Comparator() let comparisionResult = comparator(lhs: 1, rhs: 2)
Muitas pessoas sabem que ao processar valores de enumeração, é necessário descrever todos os casos e tentar não usar o padrão. Embora esse requisito adicione uma pitada de segurança, ele também tem uma desvantagem, pois ao alterar valores na enumeração, você precisa adicionar o processamento deles. Ainda existe a possibilidade de que a estrutura do sistema altere uma das enumerações, mas isso não foi processado no seu aplicativo (por exemplo, com
LABiometryType ).
O Swift 5 adicionará o atributo
desconhecido , o que permitirá que você separe 2 cenários diferentes ao processar uma enumeração:
- O código padrão deve ser executado para todos os casos não processados no switch
- Todos os casos são processados no switch e, se novos forem adicionados, você precisará usar o código no padrão
Vejamos um exemplo:
enum HTTPMethod { case post, get, put }
Livrar-se de double Opcional como resultado de chamar uma função com try? ( SE-0230 )
Certamente muitos já se depararam com o fato de que, ao chamar a função jogável, que retorna
Opcional , usando
try? , o resultado é um tipo agrupado em dois
Opcional . Isso não é muito conveniente e, portanto, no Swift 5, ligue para
tentar? nesse caso, retornará um tipo agrupado em apenas um
opcional .
Foi assim que aconteceu antes do Swift 5:
let result = try? optionalObject?.foo()
E assim será no Swift 5:
let result = try? optionalObject?.foo()
Verificação de multiplicidade ( SE-0225 )
Para verificar a multiplicidade de um número para outro, você pode usar a função
isMultiple (of :) , em vez do restante da divisão (%):
A alteração é pequena, mas torna o código um pouco mais claro e simplifica a pesquisa por código.
Contando o número de elementos em uma sequência com uma condição ( SE-0220 )
No Swift 5, o tipo Sequence adicionará o método
count (where: (Element) -> Bool) -> Int , que permitirá contar o número de elementos em uma sequência que satisfazem uma determinada condição em uma passagem. Antes disso, eu tinha que usar o
filtro em conjunto com o
count . Este método salvará a memória alocada ao criar uma nova matriz no método de
filtro .
Um exemplo:
let countOfZeroes = [0, 1, 2, 0, 4].count(where: { $0 == 0 })
Método CompactMapValues no dicionário ( SE-0218 )
Este método combina
compactMap da
matriz e
mapValues do
dicionário . Como resultado da chamada desse método, um dicionário com valores transformados é criado no qual não há valores iguais a
zero .
Um exemplo:
let dictionary = ["a": "1", "b": "2", "c": "Number"] let resultDictionary = dictionary.compactMapValues { Int($0) }
Sequências brutas ( SE-0200 )
Foi adicionada a capacidade de escrever linhas nas quais aspas e barras invertidas são usadas como caracteres regulares, e não como caracteres especiais. Para fazer isso, adicione o caractere # no início e no final da linha.
Um exemplo:
let string1 = #" " ""# let string2 = #" \ "#
Se você estiver inserindo uma variável ao criar uma linha, após a barra invertida, precisará adicionar o sinal #:
let string = #" \#(variable)"#
Se a linha tiver um sinal de #, no início e no final da linha você precisará adicionar dois sinais de ##:
let string = ##" #"##
O protocolo de sequência não contém mais o tipo associado SubSequence ( SE-0234 )
O tipo associativo de
SubSequence foi movido do protocolo
Sequence para
Collection.Agora, todos os métodos em
Sequence que retornaram
SubSequence retornam um tipo específico. Por exemplo, o método do
sufixo agora retorna uma
matriz . Aqui está a lista completa dos métodos afetados por essa alteração:
extension Sequence { public func dropFirst(_ k: Int = 1) -> DropFirstSequence<Self> public func dropLast(_ k: Int = 1) -> [Element] public func suffix(_ maxLength: Int) -> [Element] public func prefix(_ maxLength: Int) -> PrefixSequence<Self> public func drop(while predicate: (Element) throws -> Bool) rethrows -> DropWhileSequence<Self> public func prefix(while predicate: (Element) throws -> Bool) rethrows -> [Element] public func split( maxSplits: Int = Int.max, omittingEmptySubsequences: Bool = true, whereSeparator isSeparator: (Element) throws -> Bool ) rethrows -> [ArraySlice<Element>] }
Agora, trabalhar com esses métodos ficará mais fácil.
Restrições de protocolo
Os protocolos agora suportam a restrição na forma de classes que implementam esse protocolo. Em outras palavras, agora você pode indicar que um protocolo só pode ser implementado por uma classe específica. Por exemplo:
protocol Viewable: UIView {} protocol Viewable where Self: UIView {}
A segunda opção de gravação é suportada no Swift 4.2, mas pode causar um erro de compilação ou tempo de execução. No Swift 5, esse erro não ocorrerá.
Conclusão
Esta não é uma lista completa de alterações no Swift 5; apenas as principais alterações são coletadas aqui. Em geral, as mudanças apresentadas são positivas e tornam a linguagem mais compreensível e flexível. O principal é que “Converter para a sintaxe Swift atual” deve ser indolor.
Isso é tudo, obrigado pela leitura.