Hola, me llamo Ilya. Soy desarrollador de iOS en Tinkoff.ru. En este artículo, daré una breve descripción de los principales cambios en Swift 5. Estos cambios se describen en las
notas de la versión . Para aquellos que aún no se han familiarizado, ¡bienvenidos a cat!

¡El tamaño de la aplicación disminuirá!
Las aplicaciones escritas en Swift 5 y compiladas para iOS 12.2, watchOS 5.2, tvOS 12.2 no incluirán bibliotecas dinámicas para la biblioteca estándar de Swift y el SDK de Swift. Y esto significa que el tamaño de la aplicación disminuirá, sin embargo, no mucho. Si cree en
este tweet , el tamaño del proyecto vacío se redujo de 2.4 Mb a 24 Kb. Un buen resultado para aplicaciones pequeñas, pero para aplicaciones grandes no habrá mucha diferencia.
@dynamicCallable ( SE-0216 )
El atributo
@dynamicCallable le permite trabajar con un objeto como una función. Dichos objetos se denominan objetos funcionales o functores (se pueden encontrar más detalles
aquí ). Los objetos funcionales están en C ++, Python, JavaScript y otros lenguajes, y en Swift se agregaron por compatibilidad con estos lenguajes. El hecho es que Swift ahora interactúa bien con API C y Objective-C, y los desarrolladores de lenguaje quieren agregar interacción con lenguajes dinámicos: Python, JavaScript, Ruby y otros.
Para que un tipo sea un functor, debe agregar el atributo
@dynamicCallable a su declaración. Considere un ejemplo de una estructura
reductora que se puede usar para agregar números en una matriz:
@dynamicCallable struct Reducer { ... }
Luego debe implementar uno o los dos métodos siguientes:
func dynamicallyCall(withArguments: ExpressibleByArrayLiteral) func dynamicallyCall(withKeywordArguments: ExpressibleByDictionaryLiteral)
La primera función le permite acceder al objeto pasando una matriz como argumentos. La segunda función le permite acceder al objeto, pasando la misma matriz que los argumentos, pero utilizando los nombres de los argumentos.
Por ejemplo, una implementación de la primera función para una estructura
reductora se vería así:
func dynamicallyCall(withArguments arguments: [Int]) -> Int { return arguments.reduce(0, +) }
Luego aplique dicha estructura de la siguiente manera:
let reducer = Reducer() let sum = reducer(1, 2, 3)
Consideraremos la implementación del segundo método usando el ejemplo de la estructura
Comparator , con la cual podemos comparar dos 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 } }
Puede usar esta estructura de la siguiente manera:
let comparator = Comparator() let comparisionResult = comparator(lhs: 1, rhs: 2)
Muchas personas saben que cuando se procesan valores de enumeración, es necesario describir todos los casos e intentar no usar el valor predeterminado. Aunque este requisito agrega una pizca de seguridad, también tiene un inconveniente, ya que al cambiar los valores en la enumeración, debe agregar su procesamiento. Todavía existe la posibilidad de que el marco del sistema cambie algunas de las enumeraciones, pero esto no se ha procesado en su aplicación (así fue, por ejemplo, con
LABiometryType ).
Swift 5 agregará el atributo
desconocido , lo que le permitirá separar 2 escenarios diferentes al procesar una enumeración:
- El código predeterminado debe ejecutarse para todos los casos no procesados en el switch
- Todos los casos se procesan en switch, y si se agregan otros nuevos, entonces debe usar el código por defecto
Veamos un ejemplo:
enum HTTPMethod { case post, get, put }
Deshacerse de double Opcional como resultado de llamar a una función con try? ( SE-0230 )
Seguramente, muchos se han encontrado con el hecho de que al llamar a la función arrojadiza, que devuelve
Opcional , usando
try , el resultado es un tipo envuelto en dos
opcionales . Esto no es muy conveniente, por lo que en Swift 5,
¿intentas llamar
? en este caso devolverá un tipo envuelto en un solo
Opcional .
Así era antes de Swift 5:
let result = try? optionalObject?.foo()
Y así será en Swift 5:
let result = try? optionalObject?.foo()
Verificación de multiplicidad ( SE-0225 )
Para verificar la multiplicidad de un número a otro, puede usar la función
isMultiple (of :) , en lugar del resto de la división (%):
El cambio es menor, pero hace que el código sea un poco más claro y simplifica la búsqueda por código.
Contando el número de elementos en una secuencia con una condición ( SE-0220 )
En Swift 5, el tipo de secuencia agregará el
conteo (donde: (Elemento) -> Bool) -> Método
Int , que le permitirá contar el número de elementos en una secuencia que satisfacen una condición dada en una pasada. Antes de eso, tuve que usar
filter junto con
count . Este método guardará la memoria asignada al crear una nueva matriz en el método de
filtro .
Un ejemplo:
let countOfZeroes = [0, 1, 2, 0, 4].count(where: { $0 == 0 })
Método CompactMapValues en Diccionario ( SE-0218 )
Este método combina
compactMap de
Array y
mapValues de
Dictionary . Como resultado de llamar a este método, se crea un diccionario con valores transformados en el que no hay valores iguales a
nulo .
Un ejemplo:
let dictionary = ["a": "1", "b": "2", "c": "Number"] let resultDictionary = dictionary.compactMapValues { Int($0) }
Cuerdas sin procesar ( SE-0200 )
Se agregó la capacidad de escribir líneas en las que las comillas y las barras invertidas se utilizan como caracteres normales y no como caracteres especiales. Para hacer esto, agregue el carácter # al principio y al final de la línea.
Un ejemplo:
let string1 = #" " ""# let string2 = #" \ "#
Si está insertando una variable al crear una línea, luego de la barra invertida debe agregar el signo #:
let string = #" \#(variable)"#
Si la línea tiene un signo #, al principio y al final de la línea debe agregar dos signos ##:
let string = ##" #"##
El protocolo de secuencia ya no contiene la subsecuencia de tipo asociada ( SE-0234 )
El tipo asociativo de
SubSequence se ha movido del protocolo
Sequence a
Collection. Ahora todos los métodos en
Sequence que devolvieron
SubSequence devuelven un tipo específico. Por ejemplo, el método de
sufijo ahora devuelve una
matriz . Aquí está la lista completa de los métodos afectados por este cambio:
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>] }
Ahora trabajar con estos métodos será más fácil.
Restricciones de protocolo
Los protocolos ahora admiten la restricción en forma de clases que implementan este protocolo. En otras palabras, ahora puede indicar que un protocolo solo puede ser implementado por una clase específica. Por ejemplo:
protocol Viewable: UIView {} protocol Viewable where Self: UIView {}
La segunda opción de grabación es compatible con Swift 4.2, pero puede causar un error de compilación o tiempo de ejecución. En Swift 5, este error no ocurrirá.
Conclusión
Esta no es una lista completa de cambios en Swift 5; aquí solo se recopilan los principales cambios. En general, los cambios presentados son positivos y hacen que el lenguaje sea más comprensible y flexible. Lo principal es que "Convertir a la sintaxis Swift actual" debería ser sencillo.
Eso es todo, gracias por leer.