Swift 2
At the 2014 WWDC conference Apple announced Swift as a new language to write iOS app. In February 2015 they released Swift 1.2, which fixed a lot of issues (especially with the compiler) and added new language features.
In June 2015 Apple announced at WWDC Swift 2, which will be made open source later this year. In this post I will cover the new features in Swift 2.
New features in Swift 2
Println
If you want to write debug messages to the console, prior to Swift 2 you have probably used println("the message")
a lot. In Swift 2, print
now automatically prints a message on a new line. Hey … it’s all about the small things.
Enums
Enums are one of the 3 data structures in Swift and are a great way to hold a small set of data. For example
enum OSXVersion { case Lion case MountainLion case Mavericks case Yosemite case ElCapitan }
Because enums are in fact a data type, you can set a variable to be of type OSXVersion
.
var myOS:OSXVersion = .Lion
But if you were to print out the value of myOS
in Swift 1.2, you would end up with (EnumValue)
.
println(myOS) // Prints `(Enum Value)`
In Swift 2, enums now carry enough reflection to print out their value, which makes it more convenient then to print out the rawValue
of an enum prior to Swift 2.
print(myOS) // Prints `Lion`
Repeat
The do-while
loop has been renamed to repeat-while
in Swift 2.
var i = 0 do { println(i) i++ } while( i < 10 )
In Swift 2 it looks like this
var i = 0 repeat { print(i) i++ } while( i < 10 )
Option sets
Option sets are a great update for NS_OPTIONS and simplify the usage of bitflags. They are used to easily pass multiple options within one variable by using bitewise operations, but with option sets you don’t really need to worry about setting bits.
To create an option set, all you have to do is create a struct
which implements the OptionSetType
protocol. The only requirement of this protocol is that your struct has a rawValue
property.
struct FontOptions:OptionSetType { var rawValue:Int }
Now you can just add the different options you want to provide as static constants. Just make sure the rawValue of every option is a power of 2.
struct FontOptions:OptionSetType { var rawValue:Int static let StrikeThrough = FontOptions(rawValue: 1) static let Bold = FontOptions(rawValue: 2) static let Underline = FontOptions(rawValue: 4) }
To use this OptionSetType
, you just have to comma-seperate them in an array.
var style:FontOptions = [] style = [.StrikeThrough] style = [.StrikeThrough, .Bold]
And if you want to check if a certain option was set, you can use the contains
function.
if style.contains(.Bold) { // Set the style to bold }
Guard
Guard is a new statement in Swift 2 which checks a condition and bails out if the condition is not met. So what is exactly the difference between guard
and an if
statement?
Assume the following Swift 1.2 code where we have a createPerson
function which can return a Person or a String (an error message for example). As you can see we need to unwrap the dictionary and check for the values, if both values are correct we can create the Person object, otherwise we return an error message.
enum Either<A,B> { case Person(A) case Error(B) } struct Person { var name:String var age:Int } func createPerson( dictionary:AnyObject ) -> Either<Person, String> { if let name = dictionary["name"] as? String, let age = dictionary["age"] as? Int { return .Person(Person(name: name, age: age)) } return .Error( "Could not create person" ) }
With the guard
statement this code would look like this.
func createPerson( dictionary:AnyObject ) -> Either<Person, String> { guard let name = dictionary["name"] as? String, let age = dictionary["age"] as? Int else { return .Error( "Could not create person" ) } return .Person(Person(name: name, age: age)) }
Doesn’t this look a lot nicer? We’re first checking if everything is OK, if not we do an early exit out of the function scope. Otherwise we return a new Person object. The nice thing with guard is that the unwrapped values name
and age
of the guard statement are also available in the fall-through.
Availability
I’m really excited about this new feature in Swift 2. Apple finally made it easy to add SDK dependant code.
A common idiom we used was to use respondsToSelector
with an if-statement
.
if loginButton.respondsToSelector("doSomethingWithNewSDK") { // Do something }
This is highly error prone, as we can make a typo in the selector its name.
In Swift 2 you can use the #available()
directive.
if #available(iOS 9, *) { // Do something }
Error handling
Swift 2 has some new ways on how to handle errors which removes some of the typical NSError boilerplate code.
Let’s say you want to ask a webservice for some data. Your code would probably look something like this.
func getNewsFromAPI() { service.getNews() // Do something after results are received }
The problem is that service.getNews
could fail, as there might not be an internet connection. You could solve this by working with NSError, but then our code would suddenly look like this.
func getNewsFromAPI( inout error:NSError?) -> Bool { if( service.getNewsWithError(&error) ) { return false } // Do something after results are received return true }
This works … but it adds a lot of boilerplate code.
In Swift 2, we can now use the try
keyword.
func getNewsFromAPI() { try service.getNews() // Do something after results are received }
Now we’ve indicated that the getNews()
method can fail. But how do we handle the error?
That’s pretty easy, we just have to indicate that the function can throw an exception.
func getNewsFromAPI() throws { try service.getNews() // Do something after results are received }
If you want to handle the error you just wrap it inside a do-catch
statement.
func getNewsFromAPI() throws { do { try service.getNews() // Do something after results are received } catch { // Handle error } }
If the service.getNews
method throws a specific error, you can pattern match it in the catch.
func getNewsFromAPI( ) throws { do { try service.getNews() // Do something after results are received }catch NewsError.NoInternetConnection{ // Handle specific error } catch { // Handle error } }
Defining your own error types
Apple made it really easy now to create your own error types. You just have to implement the ErrorType
protocol on your class.
The easiest way is to use an enum
to hold the data for related errors. This is because enums
allow to hold extra data in the form of a payload (via associated values), and the compiler handles protocol conformance detail automatically.
So for example, say you created a class which connects to an API, you could create an APIErrors
enum, which groups the related errors that could happen when connecting to an API.
enum APIError : ErrorType { case NoInternetConnection case ServerDidNotRespond case RequestTimeOut }
Now you can just throw the error like this
if( noInternet ){ throw APIError.NoInternetConnection }
Wrapping up
As you see there are a lot of nice new features in Swift 2. I hope this give you a bit more insight in what is coming up.
To learn more, check out the following sites: