iOS Programming: New updates in SWIFT 5.1
1. Introduction
a) Released date
- On 20th September 2019, Apple released the brand new Xcode 11, featuring support for new iOS 13. And came along with that, Apple released new version of its developing language: Swift 5.1.
b) Overall
- Swift 5.1 builds on the strength of Swift 5 by extending the stable features of language to compile time with the introduction of module stability (section 2). With module stability it’s now possible to create and share binary frameworks that will work with the future releases of Swift. Swift 5.1 also extends the capabilities of the language and the standard library with new features such as property wrapper, opaque result types. Key path member lookup, diffing for appropriate collection types, and new APIs for String. Altogether the new features of Swift 5.1 make it easier to design better APIs and reduce the amount of common boilerplate code.
2. Module stability
- Swift 5.1 enables the creation of Binary frameworks that can be shared with others leveraging the language’s added support for module stability.
- Module stability defines a new text-based module interface file that describes the API of a binary framework, allowing it to be compiled with code using different versions of the compiler.
3. Standard library update
The standard library in Swift 5.1 includes some of the features below:
- Support for handling and updating diffs on collections of appropriate types.
- Increased flexibility for initializing an array.
- Additional APIs for making it easier to work with Strings, including creating and handling contiguous strings, helpers for working with Unicode text, and generic initializers for String.Index and Range.
- A variety of incremental API improvements for working with SIMD types, including support for extending vectors, reductions, and vector swizzles.
- Identifiable protocol for supporting entities that require unique identifiers.
4. Language Improvements
a) Huge improvement in auto-generated memberwise initializers
- Swift 5.1 introduces major improvements to one of Swift’s most commonly used features: memberwise initializers with default values for structs.
- In earlier versions of Swift (include Swift 5.0 and earlier versions), we have to pass all parameters to the initializer for all properties in the struct, either its properties have default values or not. A memberwise initializer was automatically created to accept parameters matching the properties of a struct , like this:
- In Swift 5.1, the memberwise initializer will use default parameter values for any properties that have them. In previous sample, we ‘ve given score property a default value 0 which means we can either pass parameter for it or leave it with default value.
- This lets us avoid repeating code. This also brings flexibilities in initializing a struct, especially when you want to creating multiple instances with have the same standard default values in their properties. But beside the good points, it is not explicit that multiple auto-generated memberwise initializers are to be declared by only one initializer function, like this:
- Like the example above, we have one function for initializing, but we can declare in 2 ways. So this is not appeared to be like a module‘s public API – that means if we want to create a library or framework, we should to define public initializers manually.
b) Implicit returns from single-expression functions
- Swift 5.1 has removed a small but important inconsistency in the language: single-expression functions that return a value can now remove the return keyword and Swift will understand it implicitly.
- For example:
- Swift 5:
- In Swift 5.1, if functions contain a single expression or just a single statement that evaluates to a value then you can leave off the return keyword, like this:
- This may make people confuse at first, but I think they will get used to it soon.
c) Opaque return types
- Swift 5.1 introduces the concept of opaque types into Swift. An opaque type is one where we‘re told about the capabilities of an object without knowing specifically what king of object it is.
- Overall, it sounds like a protocol, but opaque return types take the concept if protocols significantly further because they are able to work with associated types. They require the same type to be used internally each time, and they allow us to hide implementation details.
- As an example, if I want to create different kinds of animals, we can write code like this:
- But there is one problem. What if we compare those class’s instances. Maybe you can compare 2 Dog instances or 2 Cat instances but you cannot compare a Cat and a Dog. It does not make any sense, even though these 2 functions return Animal type. That means sometime you forgot which type of variables you have created. So I suggest to write like the following example:
d) Using Self to refer to enclosing type
- In previous versions of Swift, Self keyword 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:
- The scope of Self in Swift 5.1 version 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:
- The fact that we can now use Self above, rather than the full TextTransform type name, is of course purely syntactic sugar — but it can help make our code a bit more compact, especially when dealing with long type names. We can even use Self inline within a method or property as well, further making the above code even more compact:
- Let ‘s see some following examples
- In the first example, I print the static property poolConnections. Even after overriding the property in class ThrottleNetworkManager, it will just print out the value of its parent class. And Self comes to solve this issue, as we can see in the second picture. This brings the flexibility in extending your classes, protocols , …
e) Warnings for ambiguous none cases
- Swift’s optionals are implemented as an enum of two cases: some and none. This gave rise to the possibility of confusion if we created our own enums that had a none case, then wrapped that inside an optional.
- The optionalColor has value “nil” because Swift assumes .none means the optional is empty, rather than an optional with the value CustomColor.none.
- In Swift 5.1 this confusion now prints a warning: “Assuming you mean ‘Optional.none’; did you mean ‘CustomColor.none’ instead?” This avoids the source compatibility breakage of an error, but at least informs developers that their code might not quite mean what they thought.
f) Matching optional enums against non-optionals
- Swift has always been smart enough to handle switch/case pattern matching between optionals and non-optionals for strings and integers, but before Swift 5.1 that wasn’t extended to enums.
- In Swift 5.1 we can now use switch/case pattern matching to match optional enums with non-optionals, like this:
g) Ordered collection diffing
- Swift 5.1 gives us a new difference(from:) method that calculates the differences between two ordered collections – what items to remove and what items to insert. This can be used with any ordered collection that contains Equatable elements.
- To demonstrate this, we can create an array of scores, calculate the difference from one to the other, then loop over those differences and apply each one to make our two collections the same.
- Some of you may think that it is too simple to change an array to be the same with an array – just “assign it by the other”. But it may cause a bad performance in updating UI. For example, I have a tableview T with a datasource List. Datasource List is fetched from a web API/ web service. When the data from API changes, List will be change and tableView T will be change. And if we just assign List with a whole new dataset from the service, tableview will be reloaded completely. And there will be some lag in UI performance. With Diff API, you can easily remove or insert new rows for tableview, which helps reducing duration in updating UI.
5. Conclusion
- Swift 5.1 is still under development, and although the final branching for Swift itself has passed there is still scope to see changes from some of the other associated projects.
- Swift is now not only ABI stable, but also module stable. On top of that, Swift 5.1 also includes many small but welcome changes and tweaks that should be applicable to almost any code base.
- Beside the good points, like flexibilities in code base, there are some of features that need to be considered. The optional enums (session 4.e, 4.f) are marked as bugs and it reminds the developers to use explicit type instead, in order to avoid some external bugs in the future.
What do you think? Have you already migrated your projects to Swift 5.1? If not, try out now!
References: