Apple integrated Swift 3 into Xcode 8 beta at WWDC and will release the final version later on this year. This is the language’s first version that is open source and works both on Mac OS X and Linux. If you have followed the Swift Evolution process since December last year and even already played with it in the IBM sandbox, you know that there are a lot of changes. It is quite sure if you compile your app in Xcode 8, it will break your code.
The changes of Swift 3 can be grouped into two major categories:
- Removed features that have already been deprecated in Swift 2.2
- Language modernisation issues
Let’s start with the removed ones, since they are easier to understand and you may have encountered them before as warnings in Xcode 7.3.
++ and — Operators
The increment and decrement operators are inherited from C and their functionality is straightforward – add or subtract 1 to a certain variable:
1 2 3 4 5 |
var i = 0 i++ ++i i-- --i |
However, things get complicated when it comes to deciding which one to choose. Each of them comes in two possible flavours: prefix and postfix – they are all functions under the hood and return values which you may use or discard thanks to operator overloading.
This is overwhelming for beginners, so they have been removed – use the addition (+=) and subtraction (-=) assignment operators instead:
1 2 3 |
var i = 0 i += 1 i -= 1 |
Of course, you can use the addition (+) and subtraction (-) operators as well – the compound assignment operators approach is shorter though:
1 2 |
i = i + 1 i = i - 1 |
C-style for Loop is History
The most common usage of the increment and decrement operators is the C-style for loop. Removing the operators means that this feature is gone as well, since there is nothing you can do with it that you can’t do with the for-in control flow statement and ranges.
If you have some programming background, you probably write the for
loop like this to print the numbers from 1 to 10:
1 2 3 |
for (i = 1; i <= 10; i++) { print(i) } |
In Swift 3, you’re no longer allowed to do that. And this is its Swift 3 counterpart – notice the closed range operator (…) in action:
1 2 3 |
for i in 1...10 { print(i) } |
Alternatively, you can also use the for-each loop with closures and shorthand arguments – read more about loops here.
1 2 3 |
(1...10).forEach { print($0) } |
Remove var from Function Parameters
Function parameters are usually defined as constants, since you don’t need to modify them in its body. However, there are certain cases when declaring them as variables might come in handy. In Swift 2, you can mark a function parameter as variable with the var
keyword. Once the parameter is marked as var
, it creates a local copy of the value so you can modify its value in the body of the function.
As an example, the following function determines the greatest common divisor of two given numbers – if you skipped the Maths class back in high school, read more about it here:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
func gcd(var a: Int, var b: Int) -> Int { if (a == b) { return a } repeat { if (a > b) { a = a - b } else { b = b - a } } while (a != b) return a } |
The algorithm is simple: if both numbers are already equal, return one of them. Otherwise, compare them, subtract the smaller one from the bigger one and assign the result to the larger one until they become equal and return any one of them. As you can see, by marking a
and b
as variables, we can change their values in the function.
Swift 3 no longer allows developers to set function parameters as variables as Swift developers may get confused between var
and inout
. So the latest version of Swift simply removes var
from function parameters.
Therefore, to write the same gcd
function in Swift 3, it requires a different approach. You’ll need to save the values of the function parameters to local variables:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
func gcd(a: Int, b: Int) -> Int { if (a == b) { return a } var c = a var d = b repeat { if (c > d) { c = c - d } else { d = d - c } } while (c != d) return c } |
If you want to learn more about the motivation behind the removal, you can check out the original proposal.
Consistent Label Behaviour for Function Parameters
Function parameter lists are tuples under the hood, so you can use them to call functions, as long as the tuple’s structure matches the function’s prototype. Take the gcd()
function as an example. You can invoke the call like this:
1 |
gcd(8, b: 12) |
Or you may even call the function like below:
1 2 |
let number = (8, b: 12) gcd(number) |
As you can see, you do not need to specify the label of the first parameter in Swift 2. However, you have to specify the label of the second (and the rest of the parameters) when calling the function.
This syntax is confusing for beginners, so it is designed to standardize the label behaviour. In Swift 3, you call the function like this:
1 |
gcd(a: 8, b: 12) |
You have to explicitly specify the label of the first parameter. If you don’t do that, Xcode 8 will show you an error.
Your first reaction to this change may be “OMG! I will have to make a lot of modifications to my existing code.” You’re right. That’s tons of changes. So Apple offers a way to suppress the first parameter label of a function call. You can add an underscore to the first parameter like this:
1 2 3 4 5 |
func gcd(_ a: Int, b: Int) -> Int { ... } |
By doing this, you can invoke the function using the old way – without specifying the first label. This would make your code migration from Swift 2 to Swift 3 simpler.
Selectors as Strings No Longer Works
Let’s create a button and make it do something when you tap on it – use playgrounds only, no Interface Builder allowed:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// 1 import UIKit import XCPlayground // 2 class Responder: NSObject { func tap() { print("Button pressed") } } let responder = Responder() // 3 let button = UIButton(type: .System) button.setTitle("Button", forState: .Normal) button.addTarget(responder, action: "tap", forControlEvents: .TouchUpInside) button.sizeToFit() button.center = CGPoint(x: 50, y: 25) // 4 let frame = CGRect(x: 0, y: 0, width: 100, height: 50) let view = UIView(frame: frame) view.addSubview(button) XCPlaygroundPage.currentPage.liveView = view |
There’s quite a lot going on here, so let’s break it into steps:
- Import the UIKit and XCPlayground frameworks – you need them to create the button and show it in the playground’s assistant editor.
Note: You should enable the assistant editor in Xcode to interact with the button: View -> Assistant Editor -> Show Assistant Editor.
-
Define the tap method which fires when the user presses the button and make a responder object for the button’s target – its base class is NSObject, because selectors only work with Objective-C methods.
-
Declare the button and set its properties.
-
Declare the view and its corresponding frame, add the button to it and display it in the playground’s assistant editor.
Take a look at the highlighted code. The button’s selector is a string. If you type it wrong, the code will compile but crash at runtime, since no corresponding method can be found.
To resolve the potential issue in compile time, Swift 3 replaces string selectors with the #selector()
keyword. This enables the compiler to detect the problem early if you don’t get the method’s name right.
1 |
button.addTarget(responder, action: #selector(Responder.tap), for: .touchUpInside) |
That’s it for the removed features. Now let’s move on to the language modernisation highlights.
Key-paths as Strings
This feature is similar to the previous one, but it applies to key-value coding (KVC) and key-value observing (KVO):
1 2 3 4 5 6 7 8 9 |
class Person: NSObject { var name: String = "" init(name: String) { self.name = name } } let me = Person(name: "Cosmin") me.valueForKeyPath("name") |
You create a Person class that is key-value coding compliant, make my identity with the class designated initialiser and use the corresponding key-path to determine my name. Again, if you get it wrong, everything will blow up and I won’t be happy! 🙁
Fortunately, this will not happen in Swift 3 anymore. Key-path strings have been replaced with the #keyPath()
expression:
1 2 3 4 5 6 7 8 9 |
class Person: NSObject { var name: String = "" init(name: String) { self.name = name } } let me = Person(name: "Cosmin") me.value(forKeyPath: #keyPath(Person.name)) |
Drop NS Prefix for Foundation Types
The NS prefix goes way back for Foundation types – if you are in the mood for a history lesson, check this out. A typical example is JSON parsing:
1 2 3 4 5 |
let file = NSBundle.mainBundle().pathForResource("tutorials", ofType: "json") let url = NSURL(fileURLWithPath: file!) let data = NSData(contentsOfURL: url) let json = try! NSJSONSerialization.JSONObjectWithData(data!, options: []) print(json) |
You use Foundation classes to connect to the file and extract the JSON data in an appropriate way: NSBundle -> NSURL -> NSData -> NSJSONSerialization.
The NS prefix has been dropped in Swift 3, so it all boils down to Bundle -> URL -> Data -> JSONSerialization:
1 2 3 4 5 |
let file = Bundle.main().pathForResource("tutorials", ofType: "json") let url = URL(fileURLWithPath: file!) let data = try! Data(contentsOf: url) let json = try! JSONSerialization.jsonObject(with: data) print(json) |
M_PI vs .pi
Let’s compute the circumference and area of a circle with a given radius:
1 2 3 |
let r = 3.0 let circumference = 2 * M_PI * r let area = M_PI * r * r |
For old versions of Swift, you use M_PI
to refer to the pi constant. Swift 3 integrates the pi constant in the Float, Double and CGFloat types:
1 2 3 |
Float.pi Double.pi CGFloat.pi |
The above piece of code will be written like this in Swift 3:
1 2 3 |
let r = 3.0 let circumference = 2 * Double.pi * r let area = Double.pi * r * r |
With type inference, you can even omit the type. Here is a shorter version:
1 2 3 |
let r = 3.0 let circumference = 2 * .pi * r let area = .pi * r * r |
Grand Central Dispatch
Grand Central Dispatch (CGD) is used for networking operations that don’t block the user interface on the main thread. It’s written in C and its API is overwhelming to beginners, even for trivial tasks such as creating an asynchronous queue and making it do something:
1 2 3 4 |
let queue = dispatch_queue_create("Swift 2.2", nil) dispatch_async(queue) { print("Swift 2.2 queue") } |
Swift 3 eliminates all the boilerplate code and redundant stuff by taking an object oriented approach:
1 2 3 4 |
let queue = DispatchQueue(label: "Swift 3") queue.async { print("Swift 3 queue") } |
Core Graphics is Now More Swifty
Core Graphics is a powerful drawing framework, but it uses a C-style API similar to GCD:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
let frame = CGRect(x: 0, y: 0, width: 100, height: 50) class View: UIView { override func drawRect(rect: CGRect) { let context = UIGraphicsGetCurrentContext() let blue = UIColor.blueColor().CGColor CGContextSetFillColorWithColor(context, blue) let red = UIColor.redColor().CGColor CGContextSetStrokeColorWithColor(context, red) CGContextSetLineWidth(context, 10) CGContextAddRect(context, frame) CGContextDrawPath(context, .FillStroke) } } let aView = View(frame: frame) |
You create the view’s frame, extend the UIView class, override the drawRect() method for custom drawing and make the view with the new content.
Swift 3 takes a totally different approach – unwrap the current graphics context first and perform all drawing operations related to it afterwards:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
let frame = CGRect(x: 0, y: 0, width: 100, height: 50) class View: UIView { override func draw(_ rect: CGRect) { guard let context = UIGraphicsGetCurrentContext() else { return } let blue = UIColor.blue().cgColor context.setFillColor(blue) let red = UIColor.red().cgColor context.setStrokeColor(red) context.setLineWidth(10) context.addRect(frame) context.drawPath(using: .fillStroke) } } let aView = View(frame: frame) |
Note: The context is nil before the view calls its drawRect() method, so you unwrap it with the guard statement – read more about this here.
Verbs vs Nouns Naming Convention
Time for a little bit of grammar! 🙂 Swift 3 groups methods into two categories: methods that return a certain value – think of them as nouns – and methods that perform a certain kind of action – think of them as verbs.
Here is how you print the numbers from 10 to 1:
1 2 3 |
for i in (1...10).reverse() { print(i) } |
You use the reverse()
method to reverse the range. Swift 3 treats this operation as a noun since it returns the original range in reverse order. It adds the “ed” suffix to the method:
1 2 3 |
for i in (1...10).reversed() { print(i) } |
The most common usage of tuples is to print the contents of an array:
1 2 3 4 |
var array = [1, 5, 3, 2, 4] for (index, value) in array.enumerate() { print("\(index + 1) \(value)") } |
Swift 3 treats this method as a noun since it returns a tuple containing the array’s current index and value and adds the “ed” suffix to it:
1 2 3 4 |
var array = [1, 5, 3, 2, 4] for (index, value) in array.enumerated() { print("\(index + 1) \(value)") } |
Another example is array sorting. Here is how you sort an array in ascending order:
1 2 3 |
var array = [1, 5, 3, 2, 4] let sortedArray = array.sort() print(sortedArray) |
Swift 3 treats this method as a noun since it returns the sorted array. The sort
method is now named as sorted
:
1 2 3 |
var array = [1, 5, 3, 2, 4] let sortedArray = array.sorted() print(sortedArray) |
Let’s sort the array on the spot, without using an intermediate constant. In Swift 2, you write the code like this:
1 2 3 |
var array = [1, 5, 3, 2, 4] array.sortInPlace() print(array) |
You use sortInPlace()
to sort a mutable array. Swift 3 treats this method as a verb since it performs the actual sorting without returning anything else. It uses just the base word that describes the action. So sortInPlace()
is now renamed to sort()
:
1 2 3 |
var array = [1, 5, 3, 2, 4] array.sort() print(array) |
Swiftier APIs
Swift 3 adopts a simple philosophy for its APIs – omit needless words, so if something is redundant or can be inferred from the context, remove it:
XCPlaygroundPage.currentPage
becomesPlaygroundPage.current
button.setTitle(forState)
becomesbutton.setTitle(for)
button.addTarget(action, forControlEvents)
becomesbutton.addTarget(action, for)
NSBundle.mainBundle()
becomesBundle.main()
NSData(contentsOfURL)
becomesURL(contentsOf)
NSJSONSerialization.JSONObjectWithData()
becomesJSONSerialization.jsonObject(with)
UIColor.blueColor()
becomesUIColor.blue()
UIColor.redColor()
becomesUIColor.red()
Enumeration Cases
Swift 3 treats enumeration cases like properties, so use lowerCamelCase naming instead of upperCamelCase notation for them:
.System
becomes.system
.TouchUpInside
becomes.touchUpInside
.FillStroke
becomes.fillStroke
.CGColor
becomes.cgColor
@discardableResult
In Swift 3, Xcode will show you a warning if you do not use a return value of a function or method. Here is an example:

In the above code, the printMessage
method returns the resulting message to the caller. However, the returned value is not used. It may be a potential issue, so the compiler in Swift 3 will give you a warning.
In case, it is not a must to handle the returned value. You can suppress the warning by adding @discardableResult
to the method declaration:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
override func viewDidLoad() { super.viewDidLoad() printMessage(message: "Hello Swift 3!") } @discardableResult func printMessage(message: String) -> String { let outputMessage = "Output : \(message)" print(outputMessage) return outputMessage } |
Summary
That’s all about Swift 3. The new version of Swift is a major release that makes the language even better. It contains a lot of fundamental changes that will definitely impact your existing Swift code. I hope this tutorial helps you better understand the changes, and hopefully, save you some time to migrate your Swift project.
All the code in this tutorial can be found in this Playground project. I have tested it on Xcode 8 Beta. So make sure you use Xcode 8 to run the project.
If you have any questions or issues, please let me know. Happy coding! 🙂
Comments
starfox
AuthorGreat job!Very useful!
Cosmin
AuthorThanks – glad you like it! 🙂
Cosmin
AuthorThanks – glad you like it! 🙂
Luis Alberto Romero Calderon
AuthorGreat tutorial, those breaking changes on every swift update make me hate that languaje :/
Cosmin
AuthorThis is the last major version with so many changes – everything will be much cleaner, simpler and easier from now on.
Luis Alberto Romero Calderon
AuthorThat’s was what I thought when they release the 2.0 with breaking changes :/ But hope they handle better the next updates.
Cosmin
AuthorSwift 3 is open source and it simplifies the APIs so that’s why there are so many changes this time since the previous version – this won’t be the case for any other future releases after all for sure and for good indeed.
Cosmin
AuthorThis is the last major version with so many changes – everything will be much cleaner, simpler and easier from now on.
Siddu Halake
AuthorAwesome tutorial, I hope apple don’t do major changes in next versions of swift
Cosmin
AuthorThanks a lot – really glad you like it! 🙂
Rupesh Saxena
AuthorAny working on NSExceptions handling in Swift?
Cosmin
AuthorYou mean Swift error handling – will get to it soon! 🙂
Abhinav Roy
AuthorLife saver (y) Thanks man, really appreciate the effort.
Cosmin
AuthorThanks, glad you like it! 🙂
Shilpashree Mayigaiah
AuthorHi
What are the changes with tableviewcell in swift3,xcode8?
Cosmin
AuthorYou cand find out all about this topic in our book completely updated for iOS 10, Xcode 8 and Swift 3 here: http://www.appcoda.com/swift3-book/
Shilpashree Mayigaiah
Authorthank you
Cosmin
AuthorYou’re very welcome, don’t mention it, I wish you good luck with all of your Swift and iOS adventures and endeavours! 🙂
Shilpashree Mayigaiah
Authorthanks,glad for your wish
Amanpreet
AuthorGreat Work
Cosmin
AuthorThank you, really glad you enjoy it! 🙂
Artem Semavin
AuthorThanks a lot for this article!
We can still use “me.value(forKeyPath: “name”)”, I guess it’s easier
Cosmin
AuthorThanks, glad you like it, yes you can still use it after all indeed, but it’s error prone, as I explained in the article, so the selector version is better in this case after all for sure and for good indeed.
Yaseen Dar
AuthorNice work!
Cosmin
AuthorThanks, glad you like it!
Rajesh Panda
AuthorVery useful article !!!
Cosmin
AuthorThank you, really glad and happy you like it and enjoy it! 🙂
andrew z
Author“upperCamelCase” means “UpperCamelCase”
Cosmin
AuthorThanks for the heads up – much appreciated – will fix the typo and slip of the pen mistake as soon as possible after all for sure and for good indeed.
Priya V.R
AuthorThanks for this article,Quickly we can go through the swift 3 changes
Cosmin
AuthorThank you – glad you like the article’s content! 🙂
Amit Vijayvergiya
Authorswift is one of the best iOS programming language. We love to work with swift and waiting for its latest and updated versions.
https://www.wedigtech.com/
Sam sandy
AuthorExcellent Tutorial, thanks for the post.
App Developers
AuthorGreat tutorial, I have shared to one of my friend which she needs this info. Thanks for sharing precise info.
Ramjee Yadav
AuthorThe information you have shared is awesome. Thank you so much for sharing such beautiful information. this article is going to help out to new startups like- mobile app development companies, web application development companies.
Steven
AuthorIt’s a programming language and most of the time we use it. http://www.nbnminds.com
Bharat Go Digital
Author“Bharat Go Digital is a Startup India Blog which is also a free press release site in India.
Also read how to register company in Indiaon Bharat Go Digital.”
Tanc
AuthorThere are lots of changes in Swift 3, some of them are quite small though. But we are hoping that changes will be better in the coming years and significant than ever before.
Shibi
AuthorGreat Article. Thanks for sharing.
Very usefull
AlterYX Training
AuthorThanks for sharing such a good article.
Webtrailblazer
AuthorNice information and now Swift 5.1.3 has launched