What’s New in Swift 3?
Check out what’s new in Swift 3 – Swift’s first major release as an open source project. By Ben Morrow.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
What’s New in Swift 3?
20 mins
- Getting Started
- Migrating to Swift 3
- Implemented Swift Evolution Proposals
- API Changes
- Consistent First Argument Labels
- Omit Needless Words
- Modernized GCD and Core Graphics
- Capitalization on Enumeration Cases
- Methods that Return or Modify
- Function Types
- API Additions
- Accessing the Containing Type
- Inline Sequences
- Miscellaneous Odds and Ends
- Improvements to Tooling
- The Swift Package Manager
- Planned Future Features
- Where to Go From Here?
Modernized GCD and Core Graphics
Speaking of old API holdouts, GCD and Core Graphics have both received a much-needed makeover.
Grand Central Dispatch is used for many threading tasks such as long calculations or to communicate with a server. By moving activity to a different thread, you prevent locking up the user interface. The libdispatch library was written in the C programming language and has always used a C style API. The API has now been reimagined in native Swift [SE-0088]:
// old way, Swift 2
let queue = dispatch_queue_create("com.test.myqueue", nil)
dispatch_async(queue) {
print("Hello World")
}
// new way, Swift 3
let queue = DispatchQueue(label: "com.test.myqueue")
queue.async {
print("Hello World")
}
Similarly, Core Graphics was written in C and in the past used awkward function calls. Here’s how the new way looks [SE-0044]:
// old way, Swift 2
let context = UIGraphicsGetCurrentContext()
let startAngle: CGFloat = 0.0
let endAngle = CGFloat(2 * M_PI)
let strokeWidth: CGFloat = 1.0
let radius = self.frame.midX - strokeWidth
let center = CGPointMake(self.frame.midX, self.frame.midY)
CGContextSetStrokeColorWithColor(context, UIColor.redColor().CGColor)
CGContextSetLineWidth(context, strokeWidth)
CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0)
CGContextDrawPath(context, kCGPathStroke)
// new way, Swift 3
guard let context = UIGraphicsGetCurrentContext() else {
return
}
let startAngle: CGFloat = 0.0
let endAngle = 2 * CGFloat.pi
let strokeWidth: CGFloat = 1.0
let center = CGPoint(x: self.frame.midX, y: self.frame.midY)
let radius = self.frame.midX - strokeWidth
context.setStrokeColor(UIColor.red.cgColor)
context.setLineWidth(strokeWidth)
context.setFillColor(UIColor.clear.cgColor)
context.addArc(center: center,
radius: radius,
startAngle: startAngle,
endAngle: endAngle,
clockwise: false)
context.drawPath(using: .stroke)
Capitalization on Enumeration Cases
In another reversal from the way you’ve been used to coding Swift, lowerCamelCase now replaces UpperCamelCase for enumeration cases. This makes them more consistent with other properties – or values [SE-0006]:
// old way, Swift 2, followed by new way, Swift 3
UIStatusBarStyle.LightContent
UIStatusBarStyle.lightContent
SKLabelVerticalAlignmentMode.Center
SKLabelVerticalAlignmentMode.center
Optional<String>.None
Optional<String>.none
UpperCamelCase is now reserved solely for names of types and protocols. While this may take some getting used to, the Swift team had really good reasoning in their strive for consistency.
Methods that Return or Modify
The standard library is also getting more consistent in method naming. You choose a name based on the side effects or the actions taken. The rule of thumb is that if it includes a suffix like “-ed” or “-ing” then think of the method as a noun. A noun method returns a value. If it doesn’t have the suffix, then it is most likely an imperative verb. These “verb” methods perform the action on referenced memory. This is also known as modifying in place. There are several pairs of methods that follow this noun/verb convention in the standard library. Arrays showcase the trend well. You can use enumerate()
/enumerated()
, reverse()
/reversed()
, and sort()
/sorted()
. Previously sort()
was known as sortInPlace()
. The verbs modify the original array and the “-ed” nouns return a copy of the array. Here’s a snippet of those methods in action [SE-0006]:
var ages = [21, 10, 2] // variable, not constant, so you can modify it
ages.sort() // modified in place, value now [2, 10, 21]
for (index, age) in ages.enumerated() { // copied into a dictionarry
print("\(index). \(age)") // 1. 2 \n 2. 10 \n 3. 21
}
Function Types
Function declarations and function calls have always required parentheses around their parameters:
func f(a: Int) { ... }
f(5)
However, when you use a function type as a parameter itself, you might write something like this:
func g(a: Int -> Int) -> Int -> Int { ... } // old way, Swift 2
You probably notice that it’s fairly difficult to read. Where do the parameters end and the return types begin? With Swift 3 the correct way to define this function is [SE-0066]:
func g(a: (Int) -> Int) -> (Int) -> Int { ... } // new way, Swift 3
Now the parameter lists are surrounded by parentheses and followed by the return type. Things are clearer, and consequently, the function type is easier to recognize. Here’s a more robust comparison:
// old way, Swift 2
Int -> Float
String -> Int
T -> U
Int -> Float -> String
// new way, Swift 3
(Int) -> Float
(String) -> Int
(T) -> U
(Int) -> (Float) -> String
API Additions
While the biggest update to Swift 3 has been the modernization of the existing APIs, there is much more the Swift community has been hard at work at – including several useful additions to the Swift API as well.
Accessing the Containing Type
When you define a static property or method, you have always called them on the type directly:
CustomStruct.staticMethod()
If you are writing code in the context of a type, you still need to include the name of the type to call a static method on the type. To make this a bit cleaner, you can now call Self
to get the containing type. The capital ‘S’ refers to the type of self, whereas the lowercase ‘s’ refers to the instance of self.
Here’s how it works in action [SE-0068]:
struct CustomStruct {
static func staticMethod() { ... }
func instanceMethod() {
Self.staticMethod() // in the body of the type
}
}
let customStruct = CustomStruct()
customStruct.Self.staticMethod() // on an instance of the type
Note:This feature will be added after Swift 3.1, but it is not currently available in Xcode 8.
Note:This feature will be added after Swift 3.1, but it is not currently available in Xcode 8.
Inline Sequences
sequence(first:next:)
and sequence(state:next:)
are global functions that return infinite sequences. You give them an initial value or a mutable state and they will lazily apply a closure [SE-0094]:
for view in sequence(first: someView, next: { $0.superview }) {
// someView, someView.superview, someView.superview.superview, ...
}
You can constrain the sequence by using the prefix
manipulator [SE-0045]:
for x in sequence(first: 0.1, next: { $0 * 2 }).prefix(while: { $0 < 4 }) {
// 0.1, 0.2, 0.4, 0.8, 1.6, 3.2
}
Note:This feature is added to Swift 3.1, but it is not currently available in Xcode 8.
Note:This feature is added to Swift 3.1, but it is not currently available in Xcode 8.