https://www.swiftbysundell.com/articles/5-small-but-significant-improvements-in-swift-5-1
Swift 5.1 has now been officially released, and despite being a minor release, it contains a substantial number of changes and improvements — ranging from fundamental new features, like module stability (which enables SDK vendors to ship pre-compiled Swift frameworks), to all of the new syntax features that power SwiftUI, and beyond.
Besides its headlining new features, Swift 5.1 also contains a number of smaller — but still highly significant — new capabilities and improvements. It’s the sort of changes that at first may seem really minor, or even unnecessary, but can turn out to have a quite major impact on how we write and structure our Swift code. This week, let’s take a look at five of those features, and what kind of situations they could be useful in.
One of the many things that make structs so appealing in Swift is their auto-generated “memberwise” initializers — which enable us to initialize any struct (that doesn’t contain private stored properties) simply by passing values corresponding to each of its properties, like this:
struct Message {
var subject: String
var body: String
}
let message = Message(subject: "Hello", body: "From Swift")
These synthesized initializers have been significantly improved in Swift 5.1, since they now take default property values into account, and automatically translate those values into default initializer arguments.
Let’s say that we wanted to expand the above Message
struct with support for attachments, but that we’d like the default value to be an empty array — and at the same time, we’d also like to enable a Message
to be initialized without having to specify a body
up-front, so we’ll give that property a default value as well:
struct Message {
var subject: String
var body = ""
var attachments: [Attachment] = []
}
In Swift 5.0 and earlier, we’d still have to pass initializer arguments for all of the above properties anyway, regardless of whether they have a default value. However, in Swift 5.1, that’s no longer the case — meaning that we can now initialize a Message
by only passing a subject
, like this:
var message = Message(subject: "Hello, world!")
That’s really cool, and it makes using structs even more convenient than before. But perhaps even cooler is that, just like when using standard default arguments, we can still override any default property value by passing an argument for it — which gives us a ton of flexibility:
var message = Message(
subject: "Hello, world!",
body: "Swift 5.1 is such a great update!"
)
However, while memberwise initializers are incredibly useful within an app or module, they’re still not exposed as part of a module’s public API — meaning that if we’re building some form of library or framework, we still have to define our public-facing initializers manually (for now).
Swift’s Self
keyword (or type, really) has previously enabled us to dynamically refer to a type in contexts where the actual concrete type isn’t known — for example by referring to a protocol’s implementing type within a protocol extension:
extension Numeric {
func incremented(by value: Self = 1) -> Self {
return self + value
}
}
While that’s still possible, the scope of Self
has now been extended to also include concrete types — like enums, structs and classes — enabling us to use Self
as a sort of alias referring to a method or property’s enclosing type, like this:
extension TextTransform {
static var capitalize: Self {
return TextTransform { $0.capitalized }
}
static var removeLetters: Self {
return TextTransform { $0.filter { !$0.isLetter } }
}
}