At the end of March, Swift 5.2 was released for Xcode 11.4. It has improved error diagnosis, dependency analysis, and expanded SwiftPM functionality. An overview of some changes has already been published on Habré , in the same article the evolution of the language itself with possible examples of use is considered.
SE-0249 KeyPath as a function
Shortcut puts keyPath into a function, where the input parameter is the object itself, and the result is its property.Let's look at an example. Create an array of simple models:struct Model {
let isHidden: Bool
}
let modelArray = [Model(isHidden: true), Model(isHidden: false)]
Filter the array by the isHidden property. Below are 3 examples with the same result:
let funcIsHidden: (Model) -> Bool = \.isHidden
modelArray.filter(funcIsHidden)
modelArray.filter(\.isHidden as (Model) -> Bool)
modelArray.filter(\.isHidden)
The declared functionality does not work in the following example:
let selfFunc: (Model) -> Model = \.self
modelArray.compactMap(selfFunc)
modelArray.compactMap(\.self as (Model) -> Model)
modelArray.compactMap(\.self)
Also, unlike keyPath, autocomplet does not work.It is convenient to use for working with arrays in functions such as filter, map, reduce, sort, and the like.SR-6118 Subscripts May Contain Default Settings
All function parameters can be set to the default value. Create a Box structure that contains an array of elements, and a subscript function to access them.struct Box {
let items: [String]
subscript(_ index: Int = 0) -> String {
items[index]
}
}
Now, to access the first element, you can omit the index:let box = Box(items: ["laptop, , mobile phone"])
let firstItem = box[]
SR-2189 Local Functions Support Default Parameters from External Visibility
In everyday practice, local functions are rarely used. It can be difficult to justify their use. Nevertheless, I admit that in certain cases this may come in handy.For an example, we will create a function inside which we will describe a local one:func getXPosition() {
func calculateWidth(x: CGFloat = minX) -> CGFloat { ... }
let minX: CGFloat = 0
...
}
As the default parameter for the calculateWidth function, we can use the values within the getXPosition function.SE-0253 Using Values as Functions
Functionality, similar to @dynamicCallable, allows you to use a value as a function. But it is an implementation of the "static call".In practice, everything is extremely simple: to call functions, you can refer to values as methods.Create a Player structure:struct Player {
private(set) var isRunning = false
mutating func callAsFunction() {
isRunning.toggle()
}
}
Create an instance of Player and refer to it as a function:var player = Player()
print(player.isRunning)
player()
print(player.isRunning)
At the same time, it is forbidden to cast, and therefore, pass an object as a function:
let playerAsFunc = player as () -> Void
You can add as many methods as callAsFunction to a class, structure, or protocol:extension Player {
func callAsFunction(isRunning: Bool = false) throws { ... }
func callAsFunction() -> Bool { ... }
}
Application is possible in values that are mathematical functions, complex expressions or in cases where the value has one dominant function. Nevertheless, you should not abuse this functionality, as it can be misleading.SR-4206 Fixed bug with function overriding with generic parameter
Now, overriding the function, you cannot change or add restrictions on the generic type. As an example, create a CarBuilder class and inherit from it by overriding the add method:protocol PowerfullEngine { }
class CarBuilder {
func add<T>(engine: T) {}
}
class MercedesBuilder: CarBuilder {
override func add<T>(engine: T) {}
override func add<T: PowerfullEngine>(engine: T) {}
}
SR-11298 Extending a protocol without class restrictions inherits this restriction
In the case of restrictions on Self, the extension will apply the restriction.For example, create the Menu and extension protocol with a class restriction:protocol Menu {}
class SideMenu: Menu {
var sectionHeight = 0
}
extension Menu where Self: SideMenu {
var menuHeight: Int {
get { sectionHeight * 20 }
set { sectionHeight = newValue / 20 }
}
}
At the same time, the setter is nonmutating, as if the protocol has a class restriction.SR-11429 Casting for functions with labels
When casting functions to type labels are now removed. Thanks to this, you can cast functions with labels. Previously, this functionality worked only in functions without labels:func setX(x: Int) {}
(setX as (Int) -> Void)(5)
However, the default values will not be saved:func setPoint(x: Int, y: Int = 0) {}
(setPoint as (Int, Int) -> Void)(5, 1)
This also applies to generics, so this code is no longer valid.typealias Point<T> = T
func set(x: Int) {}
(set as Point)(5)
(set as Point)(x: 5)
SR-11841 The filter (_ :) function is called in the expected order in lazy collections
Create a lazy collection and call the count method:let lazyArray = [0]
.lazy
.filter { _ in print("A"); return true }
.filter { _ in print("B"); return true }
_ = lazyArray.count
Before the result of the call was the opposite: B A.SR-2790 A number of type initializers of the UnsafePointer / UnsafeBufferPointer family now issue a warning
The restriction applies to strings, arrays, and inout parameters that do not exist outside of the function call.Create a structure that takes UnsafePointer as a parameter during initialization:struct Game {
let info: UnsafePointer<Int8>
}
func createGame() {
var i: Int8 = 0
_ = Game(info: .init(&i))
_ = Game(info: [1, 2])
_ = Game(info: "")
}
There were 9 changes in this version, however, they definitely introduced new functionality. I assume that the most used of the current ones will be KeyPath as a function.And we look forward to the next version. Apparently, it will support Swift on Windows and interesting features will appear, such as the use of self in escaping closures without accessing through self. * ( SE-0269 ) and the functionality of generics ( SE-0267 ) will expand .Source