With Swift 2.0 already out, most of the community is already familiar with the major new features, including reflection, error handling and Objective-C generics, which we’ve covered on our blog before. But the latest Swift version includes many other lesser-known functionalities, some of which I would like to discuss today.
With Swift 2.0 already out, most of the community is already familiar with the major new features, including reflection, error handling and Objective-C generics, which we’ve covered on our blog before. But the latest Swift version includes many other lesser-known functionalities, some of which I would like to discuss today. Without further ado, let’s start with...
Have you ever wondered why you can instantiate a Selector using "string literals", or why you can use [.Array, .Literals] to create option sets? Well, this is not some kind of compiler magic – Swift offers native, protocol-driven support for implementing such literal convertibles. Swift offers the following protocols:
ArrayLiteralConvertible (used by Array, Set, OptionSetType)
BooleanLiteralConvertible (used by Bool)
DictionaryLiteralConvertible (used by Dictionary)
FloatLiteralConvertible (used by Float, Double)
NilLiteralConvertible (used by Optional, Selector, UnsafePointer)
IntegerLiteralConvertible (used by Int, Float, Double)
StringLiteralConvertible (used by String, Character, Selector)
Now, consider the following RegularExpression type:
You may use StringLiteralConvertible to make it instantiable using only a string literal – I won’t tell you how, though! Consider it homework.
Now let’s pretend you’re developing a scientific application. You need an enum to represent a bit, which you then use to compose a string of zeroes and ones.
Not exactly what you were expecting, right? The reason behind this output is that because Bit doesn’t conform to CustomStringConvertible (previously Printable), the interpolation mechanism implicitly uses reflection to determine the string representation – and the default mirror produces just the name of a case.
Of course, you could make your type conform to CustomStringConvertible and fix the issue, but where’s the fun in that? Let’s use another less well-known Swift protocol, StringInterpolationConvertible.
The main difference between StringInterpolationConvertible and StringLiteralConvertible is that you don’t implement it on your type – instead, you need to extend String by overloading init<T>(stringInterpolationSegment: T):
Hooray! That’s way better.
Advanced Objective-C Bridging
When Apple first revealed Swift, developers quickly came to the conclusion that it was created with interoperability in mind. Today we all know there are several ways to make your Swift code work with Objective-C and vice versa. Let’s review our options:
Inherit a Swift class from an Objective-C class – that way the Swift class is automatically visible to Objective-C code.
Use the @objc attribute – we may explicitly mark whole classes, protocols or methods as visible to Objective-C.
Take advantage of bridging headers – for our Objective-C classes to be visible in Swift.
And that’s basically it… or is it? Let’s examine the following code:
How in the name of Chris Lattner is the above code compiling? Well, after digging into Swift’s standard library, we notice that Array actually conforms to a mysterious protocol: _ObjectiveCBridgeable. And here’s its interface:
Now you’re asking – what’s the proper way of implementing it and what are you gaining? This time, imagine you’re developing a geometry app and need to represent a point (without using CoreGeometry, obviously). Consider the following types:
After making Point conform to _ObjectiveCBridgeable (you can see how in the attached slides or a demo playground), the following code actually compiles with no warnings whatsoever:
And that, ladies and gentlemen, is how all interoperable types in Swift are implemented.
These were only three of the many hidden functionalities in Swift. To search for such gems, I would recommend digging into Swift’s standard library, using LLDB type lookup, and, most importantly, experimenting in playgrounds over and over again.