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.
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.
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.
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:
The reverse process to decode a string works very similarly, thanks to the
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
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
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 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:
nameKeyPath object describes a reference to the
name property. It can then be used as a subscript on that object.
If you change the variable from
wwdc, you can also modify a specific property via the key-path subscript syntax.
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:
endIndex had to be specified. Now, a shorter syntax exists:
Or, if you want to begin with the start index:
The same syntax can also be used for pattern matching in a
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:
Dictionary and Set Improvements
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.
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.
filter Return Type
filter method now returns an object of the same type you’re filtering with.
Defaults for Dictionary Lookup
When working with dictionaries, you can provide a default value when using the subscript syntax to avoid having to later unwrap an optional.
Dictionary Grouping Initializer
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.