The latest Xcode 10.2 beta release includes support for Swift 5. In addition to bringing new features at the language and tooling level, this new release produces smaller binary packages for iOS 12.2 by not including the Swift runtime in the app bundle.
The possibility of not packaging a runtime within app bundles is a direct consequence of Swift 5 ABI stability, a feature that has been on Swift's horizon since Swift 3. Besides shrinking app sizes, ABI stability will also enable the use of binary frameworks that are not tied to the compiler used to build them and that are binary-compatible with multiple, including future Swift versions. According to the Swift ABI stability roadmap, all major tasks that were required to implement ABI stability are now complete, except for writing up the relevant technical specifications. Those include type metadata, calling conventions, and data layout.
On the language front, this beta introduces a number of new features:
- You can now call types annotated with the new
@dynamicallyCallable
attribute as if they were functions, in a similar way tooperator()
in C++ and Python callable objects. For example, you can write:@dynamicCallable struct ToyCallable { func dynamicallyCall(withArguments: [Int]) {} func dynamicallyCall(withKeywordArguments: KeyValuePairs<String, Int>) {} } let x = ToyCallable() x(1, 2, 3)
Along with the
@dynamicMemberLookup
introduced in Swift 4.2,@dynamicallyCallable
aims to extend interoperability with dynamic languages like Python, JavaScript, Perl, and Ruby. For example, if you have a Python class:# Python class: class Dog: def __init__(self, name): self.name = name self.tricks = [] # creates a new empty list for each `Dog` def add_trick(self, trick): self.tricks.append(trick)
you could import it in Swift using an interoperability layer and call its method in a more natural way:
// import DogModule.Dog as Dog let Dog = Python.import("DogModule.Dog") let dog = Dog("Brianna") // in Swift 4.2, this would be let dog = Dog.call(with: "Brianna") dog.add_trick("Roll over") // in Swift 4.2, this would be dog.add_trick.call(with: "Roll over") let dog2 = Dog("Kaylee").add_trick("snore") // in Swift 4.2, this would be Dog.call(with: "Kaylee").add_trick.call(with: "snore")
- Keypaths in Swift 5 support the
\.self
syntax to refer to the entire input value:let id = \Int.self var x = 2 print(x[keyPath: id]) // Prints "2" x[keyPath: id] = 3 print(x[keyPath: id]) // Prints "3"
- If you apply
try?
to an optional type you will get a flattened optional, instead of a nested optional:// x is Bar?? in Swift 4.2 and Bar? in Swift 5 let x = try? foo?.makeBar() // dict is [String: Any]?? in Swift 4.2, [String: Any]? in Swift 5 let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any]
- The new
ExpressibleByStringInterpolation
protocol, which supersedes_ExpressibleByStringInterpolation
, improves string interpolation performance, efficiency, and clarity.
Several of Swift 5 new language features are not backward compatible and require an update to Swift 4.2 code. While Xcode 10.2 remains in beta, you will want to make sure your Swift code remains compatible with Xcode 10.1, which is the only Xcode version that can be used to submit apps to the App Store. You can do this using conditional compilation, like in this example:
#if compiler(<5)
// Swift 4.2 version
#else
// Swift 5 version
#endif
Additionally, it is worth noting that Xcode 10.2 removes support for Swift 3, so you better migrate your Swift 3 code to Swift 4.2 using Xcode 10.1 before moving to Xcode 10.2.
This is just a short introduction of the most significant changes in Swift 5, which also includes features added to the Swift Standard Library and the Swift Package Manager, and improvements to the compiler. If you are interested in the full detail, do not miss the official announcement. You can download Xcode 10.2, and the related iOS SDK 12.2, available to any registered developer, from Apple download page.