Swift 5.2. Resumen de todos los cambios

A finales de marzo, se lanz贸 Swift 5.2 para Xcode 11.4. Ha mejorado el diagn贸stico de errores, el an谩lisis de dependencia y la funcionalidad expandida de SwiftPM. Ya se ha publicado una descripci贸n general de algunos cambios en Habr茅 , en el mismo art铆culo se considera la evoluci贸n del lenguaje en s铆 con posibles ejemplos de uso.


 

SE-0249 KeyPath como una funci贸n


El acceso directo pone keyPath en una funci贸n, donde el par谩metro de entrada es el objeto mismo, y el resultado es su propiedad.

Veamos un ejemplo. Cree una matriz de modelos simples:

struct Model {
    let isHidden: Bool
}
 
let modelArray = [Model(isHidden: true), Model(isHidden: false)]

Filtre la matriz por la propiedad isHidden. A continuaci贸n hay 3 ejemplos con el mismo resultado:

// 1
let funcIsHidden: (Model) -> Bool = \.isHidden
modelArray.filter(funcIsHidden)
 
// 2
modelArray.filter(\.isHidden as (Model) -> Bool)
 
// 3
modelArray.filter(\.isHidden)

La funcionalidad declarada no funciona en el siguiente ejemplo:

//   
let selfFunc: (Model) -> Model = \.self
modelArray.compactMap(selfFunc)
 
// ERROR: Expression type '(Model) -> Model' is ambiguous without more context
modelArray.compactMap(\.self as (Model) -> Model)
 
// ERROR: Key path value type 'Optional<_>' cannot be converted to contextual type '_'
modelArray.compactMap(\.self)

Adem谩s, a diferencia de keyPath, el autocompletado no funciona.

Es conveniente usarlo para trabajar con matrices en funciones como filtro, mapa, reducci贸n, clasificaci贸n y similares.

Los sub铆ndices SR-6118 pueden contener configuraciones predeterminadas


Todos los par谩metros de la funci贸n se pueden establecer en el valor predeterminado. Cree una estructura de cuadro que contenga una matriz de elementos y una funci贸n de sub铆ndice para acceder a ellos.

struct Box {
    let items: [String]
    
    subscript(_ index: Int = 0) -> String {
        items[index]
    }
}

Ahora, para acceder al primer elemento, puede omitir el 铆ndice:

let box = Box(items: ["laptop, , mobile phone"])
let firstItem = box[] // "laptop"

Las funciones locales SR-2189 admiten par谩metros predeterminados desde la visibilidad externa


En la pr谩ctica diaria, las funciones locales rara vez se utilizan. Puede ser dif铆cil justificar su uso. Sin embargo, admito que en ciertos casos esto puede ser 煤til.

Por ejemplo, crearemos una funci贸n dentro de la cual describiremos una local:

func getXPosition() {
    func calculateWidth(x: CGFloat = minX) -> CGFloat { ... }
    let minX: CGFloat = 0
    ...
}

Como par谩metro predeterminado para la funci贸n CalculateWidth, podemos usar los valores dentro de la funci贸n getXPosition.

SE-0253 Uso de valores como funciones


La funcionalidad, similar a @dynamicCallable, le permite usar un valor como funci贸n. Pero es una implementaci贸n de la "llamada est谩tica".

En la pr谩ctica, todo es extremadamente simple: para llamar a funciones, puede referirse a los valores como m茅todos.

Crear una estructura de jugador:

struct Player {
    private(set) var isRunning = false
    
    mutating func callAsFunction() {
        isRunning.toggle()
    }
}

Cree una instancia de Player y cons煤ltela como una funci贸n:

var player = Player()
print(player.isRunning) // false
player()
print(player.isRunning) // true

Al mismo tiempo, est谩 prohibido lanzar y, por lo tanto, pasar un objeto como una funci贸n:

// ERROR: Cannot convert value of type 'Player' to type '() -> Void' in coercion
let playerAsFunc = player as () -> Void

Puede agregar tantos m茅todos como callAsFunction a una clase, estructura o protocolo:

extension Player {
    func callAsFunction(isRunning: Bool = false) throws { ... }
    func callAsFunction() -> Bool { ... }
}

La aplicaci贸n es posible en valores que son funciones matem谩ticas, expresiones complejas o en casos donde el valor tiene una funci贸n dominante. Sin embargo, no debe abusar de esta funcionalidad, ya que puede ser enga帽osa.

SR-4206 Error solucionado con anulaci贸n de funci贸n con par谩metro gen茅rico


Ahora, anulando la funci贸n, no puede cambiar ni agregar restricciones en el tipo gen茅rico. Como ejemplo, cree una clase CarBuilder y herede de ella anulando el m茅todo add:

protocol PowerfullEngine { }
 
class CarBuilder {
  func add<T>(engine: T) {}
}
 
class MercedesBuilder: CarBuilder {
    //  
    override func add<T>(engine: T) {}
    // ERROR: Overridden method 'add' has generic signature <T where T : PowerfullEngine> which is incompatible with base method's generic signature <T>; expected generic signature to be <T>
    override func add<T: PowerfullEngine>(engine: T) {}
}

SR-11298 Extender un protocolo sin restricciones de clase hereda esta restricci贸n


En el caso de restricciones en Self, la extensi贸n aplicar谩 la restricci贸n.

Por ejemplo, cree el men煤 y el protocolo de extensi贸n con una restricci贸n de clase:

protocol Menu {}
 
class SideMenu: Menu {
  var sectionHeight = 0
}
 
extension Menu where Self: SideMenu {
  var menuHeight: Int {
    get { sectionHeight * 20 }
    set { sectionHeight = newValue / 20 }
  }
}

En este caso, el configurador no es mutante, como si el protocolo tuviera una restricci贸n de clase.

SR-11429 Fundici贸n para funciones con etiquetas


Cuando las funciones de conversi贸n para escribir etiquetas ahora se eliminan. Gracias a esto, puede emitir funciones con etiquetas. Anteriormente, esta funcionalidad solo funcionaba en funciones sin etiquetas:

func setX(x: Int) {}
(setX as (Int) -> Void)(5)

Sin embargo, los valores predeterminados no se guardar谩n:

func setPoint(x: Int, y: Int = 0) {}
(setPoint as (Int, Int) -> Void)(5, 1)

Esto tambi茅n se aplica a los gen茅ricos, por lo que este c贸digo ya no es v谩lido.

typealias Point<T> = T
func set(x: Int) {}
 
//  
(set as Point)(5) 
 
// ERROR: Extraneous argument label 'x:' in call
(set as Point)(x: 5) 

SR-11841 La funci贸n de filtro (_ :) se llama en el orden esperado en colecciones diferidas


Cree una colecci贸n perezosa y llame al m茅todo de conteo:

let lazyArray = [0]
    .lazy
    .filter { _ in print("A"); return true }
    .filter { _ in print("B"); return true }
 
//  A B
_ = lazyArray.count

Antes, el resultado de la llamada era lo contrario: B A.

SR-2790 Varios inicializadores de tipo de la familia UnsafePointer / UnsafeBufferPointer ahora emiten una advertencia


La restricci贸n se aplica a cadenas, matrices y par谩metros de entrada que no existen fuera de la llamada a la funci贸n.

Cree una estructura que tome UnsafePointer como par谩metro durante la inicializaci贸n:

struct Game {
    let info: UnsafePointer<Int8>
}
 
func createGame() {
    var i: Int8 = 0
    
    // WARNING: Initialization of 'UnsafePointer<Int8>' results in a dangling pointer
    _ = Game(info: .init(&i))
    
    // WARNING: Passing '[Int8]' to parameter, but argument 'character' should be a pointer that outlives the call to 'init(character:)'
    _ = Game(info: [1, 2])
    
    // WARNING: Passing 'String' to parameter, but argument 'character' should be a pointer that outlives the call to 'init(character:)
    _ = Game(info: "")
}

Hubo 9 cambios en esta versi贸n, sin embargo, definitivamente introdujeron una nueva funcionalidad. Supongo que el m谩s utilizado de los actuales ser谩 KeyPath como una funci贸n.

Y esperamos la pr贸xima versi贸n. Aparentemente, admitir谩 Swift en Windows y aparecer谩n caracter铆sticas interesantes, como el uso de self para escapar de los cierres sin acceder a trav茅s de self. * ( SE-0269 ) y la funcionalidad de los gen茅ricos ( SE-0267 ) se ampliar谩 .

Fuente

All Articles