What's New in Swift 4

Swift 4 has been in the works for the last few months. If you're like me, you might follow Swift Evolution to stay up to date with all the proposals and changes. Even if you do, now is a good time to review all the additions and changes to the language in this new iteration.

A snapshot of Swift 4 was already available a few weeks before Xcode 9 was announced at WWDC 2017. In this post you'll learn all about the new features introduced in Swift 4—from brand new APIs to improvements to the language syntax.

Let's first see how you can get the new compiler installed on your machine.

Xcode Setup

There are two ways to run Swift 4. You can either install the Xcode 9 beta if you have a developer account with access to it or you can set up Xcode 8 to run with a Swift 4 snapshot. In the former case, download the beta from your developer account download page.

If you prefer to use Xcode 8, simply head over to Swift.org to download the latest Swift 4.0 Development snapshot. Once the download finishes, double-click to open the .pkg file, which installs the snapshot.

Switch to Xcode now and go to Xcode > Toolchains > Manage Toolchains. From there, select the newly installed Swift 4.0 snapshot. Restart Xcode and now Swift 4 will be used when compiling your project or playground. Note that all the code presented in this tutorial is also available in a GitHub repo.

New Features

Let's take a look at the new features added to Swift 4. One caveat: the language is still in beta, and we will most likely see more changes and bug fixes before the official version is released. Moreover, some of the most recently approved proposals may still not be implemented at this time, so keep an eye on future release notes to see what will be implemented and fixed.

Encoding and Decoding

JSON parsing is one of the most discussed topics in the Swift community. It's great to see that someone finally took care of writing proposals SE-0166 and SE-0167 and pushed the idea to refresh the archival and serialization APIs in the Foundation framework. In Swift 4, there is no longer any need to parse or encode your class, struct or enum manually.

New Encodable and Decodable protocols have been added, and you can make your classes conform to them by simply adding Codable (which is an alias for Decodable & Encodable) to the class's inheritance list. Then you can use the JSONEncoder to encode an instance of the class:

As you can see, you instantiate a JSONEncoder object to convert the struct to a JSON string representation. There are a few settings that you can tweak to get the exact JSON format you need. For example, to set a custom date format, you can specify a dateEncodingStrategy in the following way:

As you can see, by passing the type of the object to the decode method, we let the decoder know what object we expect back from the JSON data. If everything is successful, we'll get an instance of our model object ready to be used.

That's not even all the power and the modularity of the new API. Instead of using a JSONEncoder, you can use the new PropertyListEncoder and PropertyListDecoder in case you need to store data in a plist file. You can also create your own custom encoder and decoder. You only need to make your decoder conform to the Decoder and your encoder to the Encoder protocol.

Strings

As part of the String Manifesto, the String type also received quite a big refresh. It now conforms once again (after being removed in Swift 2) to the Collection protocol thanks to proposal SE-0163. So now you can simply enumerate over a string to get all characters.

Substring is a new type that conforms to the same StringProtocol to which String also conforms. You can create a new Substring by just subscripting a String. The following line creates a Substring by omitting the first and last character.

A nice addition that should make it easier to work with big pieces of text is multi-line strings. If you have to create a block of text which spans across multiple lines, you previously had to manually insert \n all over the place. This was very inelegant and difficult to manage. A better way now exists to write multi-line strings, as you can see from the following example:

There are few rules that go along with this new syntax. Each string begins with a triple quotation mark ("""). Then, if the entire string is indented, the spacing of the closing characters decides the spacing to be stripped from each line in the string. For example, if the closing character is indented by 2 tabs, the same amount will be removed from each line. If the string has a line that doesn't have this amount of spacing, the compiler will throw an error.

Key Paths

Key paths were added in Swift 3 to make it easier to reference properties in an object. Instead of referencing an object key with a simple string literal, key paths let us enforce a compile-time check that a type contains the required key—eliminating a common type of runtime error.

Key paths were a nice addition to Swift 3, but their use was limited to NSObjects and they didn't really play well with structs. These were the main motivations behind proposal SE-0161 to give the API a refresh.

A new syntax was agreed by the community to specify a key path: the path is written starting with a \. It looks like the following:

One-Sided Ranges

SE-0172 proposed to add new prefix and postfix operators to avoid unnecessarily repeating a start or end index when it can be inferred. For example, if you wanted to subscript an array from the second index all the way to the last one, you could write it in the following way:

Previously, the endIndex had to be specified. Now, a shorter syntax exists:

let positive = numbers[2...]

Or, if you want to begin with the start index:

let negative = numbers[...1]

The same syntax can also be used for pattern matching in a switch statement.

Generic Subscripts

Before Swift 4, subscripts were required to define a specific return value type. SE-0148 proposed the possibility of defining a single generic subscript that would infer the return type based on the defined result value. Aside from the type annotation, it works pretty much the same way as before.

As you can see, this really improves the readability of your objects in the cases where you need to access them via the subscript syntax.

Class and Subtype Existentials

One of the missing features from the Swift type system to date has been the ability to constrain a class to a specific protocol. This has been fixed in Swift 4—you can now specify the type of an object and the protocols to which it has to conform, thanks to SE-0156. You can, for example, write a method that takes a UIView that conforms to the Reloadable protocol with the following syntax:

func reload(view: UIView & Reloadable) {
}

Dictionary and Set Improvements

Dictionary and Set also received a nice refresh in Swift 4. They are much more pleasant to use thanks to a few utility methods that have been added.

mapValues

Dictionary now has a mapValues method to change all values, avoiding the use of the generic map method that requires working with key, value tuples.

Dictionary Grouping Initializer

Finally, a Dictionary(grouping:) initializer has been introduced to facilitate creating a new dictionary by grouping the elements of an existing collection according to some criteria.

In the following examples, we create a dictionary by grouping together all conferences that have the same starting letter. The dictionary will have a key for each starting letter in the conferences collection, with each value consisting of all keys that start with that letter.

Conclusion

Now that you have taken a look at some of the major new features in Swift 4, you're probably champing at the bit to start using them, to help keep your codebase fresh and clean. Start to write your new code to take advantage of the useful new features and think about refactoring some of your previous code to make it simpler and easier to read.