As we all know for a long time, Apple has integrated Swift 3 into Xcode 8. This is the first version of the open source language that works on both macOS and Linux. If you followed the development of the language on Swift Evolution since December last year and managed to experiment with it at the IBM sandbox, you probably already understood that a lot of changes appeared in it. I’m pretty sure that when compiling an existing project in Xcode 8, your code will surprise you with errors. But it is fixable. Let's get acquainted with some changes in the new versions of the language.

Changes in the new versions can be divided into two main categories:
- Remote functions that are already deprecated with Swift 2.2
- Language enhancements
Let's start with the category of remote functions, since it is easier to understand and you probably met with these functions when you received warnings in Xcode 7.3.
Operators ++ and -
The increment and decrement operators of the heritage of the C language and their functionality is simple - add one or subtract one to a specific variable:
')
var i = 0 i++ ++i i-- --i
However, things get more complicated when it comes to deciding which one to choose. Each of them can be presented in two possible variants: prefix and postfix - they all function thanks to the engine and return values ​​that you can use or reject due to operator reloading.
This is more than enough for beginners, since they have been removed - use the assignment and addition operators
+ = and subtraction
- = instead of:
var i = 0 i += 1 i -= 1
Of course, you can use addition (+) and subtraction (-) operators, as well as share assignment operators, so you can save your time when writing code, though:
i = i + 1 i = i - 1
For your reference: If you want to know more about the reasons for this change, see Chris Latner's suggestion on this.C language style for writing cycles is history
The most common example of using increment and decrement operators is the C language style for writing a loop. Removing operators means deleting everything connected with them, because you can’t do anything with it all, unlike what you did with expressions and the operator to specify a range.
For example, if you have some knowledge, you will probably use a for loop to display a number from 1 to 10:
for (i = 1; i <= 10; i++) { print(i) }
In Swift 3, this is not possible. This is its prototype in Swift 3 - let's consider the closed-range operator (...) in action:
for i in 1...10 { print(i) }
Alternatively, you can also use for-each loop with closed expressions and abbreviated arguments — you can find more detailed information
here .
(1...10).forEach { print($0) }
For your reference: If you want to learn more about the motivation for this change, see Erica Sadun's proposal .Removed variable from function parameters
Function parameters are usually defined as constants since they do not need to be changed inside functions. However, there are certain instances where declaring them as variables can be useful. In Swift 2, you can mark a function parameter as a variable with the
var keyword. After the parameter is specified as
var , it will create a local copy of the value, so you can change its value in the function body.
As an example, the following function defines the greatest common factor of two given numbers — if you missed a math course in high school, read more about it here:
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, one of them is returned. Otherwise, compare them, subtract the smaller of the larger and assign the result to the larger until they are equal and return any 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, because Swift developers can get confused between
var and
inout . Thus, the latest version of Swift simply removes the
var from the function parameters.
Therefore, to write the same
gcd function in Swift 3, a different approach is needed. You need to save the values ​​of the function parameters for local variables:
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 know more about the reasons for this decision, you can
read the original sentence .
Consistent labeling behavior for function parameters
Function parameter lists are tuples, so you can use them to call functions, as long as the structure of the tuple matches the function prototype. Take gcd () as an example. You can make a call like this:
gcd(8, b: 12)
Or you can even call a function, as shown below:
let number = (8, b: 12) gcd(number)
As you can see in Swift 2, you do not need to specify the label of the first parameter. However, you must specify a label for the second (and other parameters) when calling the function.
This syntax is confusing for novice developers, so it is intended to standardize the behavior of tags. In the new versions of the Swift language, you can call a function as follows:
gcd(a: 8, b: 12)
You must explicitly specify a label for the first parameter. If you do not do this, Xcode 8 will show you an error message.
Your first reaction to this change might look like “OMG! I have to make a lot of changes to the existing code. ” You're right. These are tons of changes. Thus, Apple offers a way to suppress the first label of the parameter of the function call. You can add an underscore to the first parameter, as shown below:
func gcd(_ a: Int, b: Int) -> Int { ... }
By doing this, you can call a function using the old method - without specifying the first label. This will help make code migration from Swift 2 to Swift 3 much easier.
On the motivation and intent of this change, you can
read this sentence .
Selectors as strings are no longer used.
Let's create a button and perform some action, when you click on it - use only the playground, not the storyboard:
There are quite a few events going on, so let's break them down into stages:
- Import of UIKit and XCPlayground frameworks - you need to create a button and show it in the playground editor.
- Determine the click method that will be executed when the user clicks a button and create a target? the button logical entity is its base class NSObject, since selectors work only with Objective-C methods.
- Button declaration and setting properties.
- Creating a view of a certain size, adding a button to the view and displaying it in the Playground assistant.
Look at the highlighted code. The button selector is a string. If you enter it incorrectly, the code will be compiled, but it will fail during its execution, since the corresponding method may not be found.
To eliminate a potential compile-time problem, Swift 3 replaced the selector string with the #selector () keyword. This allows the compiler to detect the problem earlier if you do not correctly specify the name of the method.
button.addTarget(responder, action: #selector(Responder.tap), for: .touchUpInside)
To understand the reasons for this change, you can
read Doug Gregor's proposal .
This is with regard to remote functions. Now let's get to the main points of language modernization.
Key-paths as a string
This function is similar to the previous one, but it refers to
key value coding (KVC) and key-value observing (KVO):
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 matches the key-value of the encoding, create my identity with the class designated by the initializer, and use
KVC to set the name.
Again, if you make it wrong, everything will explode!
Fortunately, this will not happen again in Swift 3. Key-path has been replaced by the #keyPath () expression:
class Person: NSObject { var name: String = "" init(name: String) { self.name = name } } let me = Person(name: "Cosmin") me.value(forKeyPath: #keyPath(Person.name))
To understand the reasons for this change, you can
read David Hearts’s suggestion .
Removed NS base type prefix
Removed
NS prefix for base types. Let's see how it works. A typical example is working with JSON:
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 can use base classes to connect to a file and extract data in JSON format appropriately:
NSBundle -> NSURL -> NSData -> NSJSONSerialization.The
NS prefix in Swift 3 is not used, so it all comes down to
Bundle -> URL -> Data -> JSONSerialization (): 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)
For this procedure for changing the naming, you can check out this sentence
written by Tony Parker and Philip Hausler.M_PI vs .pi
Let's calculate the circles and the area of ​​a circle with a given radius:
let r = 3.0 let circumference = 2 * M_PI * r let area = M_PI * r * r
For older versions of Swift, you use
M_PI to denote the constant
pi . Swift 3 integrates the constant
pi into the type
Float ,
Double and
CGFloat :
Float.pi Double.pi CGFloat.pi
The above code snippet will be written like this in Swift 3:
let r = 3.0 let circumference = 2 * Double.pi * r let area = Double.pi * r * r
With the help of inference type, you can even omit the type. Here is the short version:
let r = 3.0 let circumference = 2 * .pi * r let area = .pi * r * r
Grand central dispatch
Grand Central Dispatch is used for network operations that do not block the user interface in the main thread. It is written in C and its API is very complex for novice developers, even to perform simple tasks, such as creating an asynchronous queue and performing some operations:
let queue = dispatch_queue_create("Swift 2.2", nil) dispatch_async(queue) { print("Swift 2.2 queue") }
Swift 3 eliminates all template code and redundant material by adopting an object-oriented approach:
let queue = DispatchQueue(label: "Swift 3") queue.async { print("Swift 3 queue") }
For more information about this change, you can
read written by Matt Wright .
Core Graphics now more Swifty
Core Graphics is a powerful graphical framework, but it uses a C-like interface similar to GCD:
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 a view frame by extending the UIView class by overriding the DrawRect () method.
Swift 3 takes a completely different approach - first it expands the current graphics context and performs all the drawing operations that are subsequently associated with it:
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 will be null before calling the DrawRect () method, so you need to expand it using the guard expression — more on this here .Convention on the naming of verbs and nouns
Time for grammar! The groups of methods in Swift 3 fall into two categories: methods that return some meaning — implied as nouns — and methods that perform a certain kind of action — implied as verbs.
Here you can output from 10 to 1:
for i in (1...10).reverse() { print(i) }
You use the
reverse () method to change the range. Swift 3 treats this operation as a noun, as it returns the original range in reverse order. It adds the “ed” suffix to the method:
for i in (1...10).reversed() { print(i) }
The most common use of tuples is to output the contents of an array:
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 current index and value of this array, and adds the suffix “ed” to it:
var array = [1, 5, 3, 2, 4] for (index, value) in array.enumerated() { print("\(index + 1) \(value)") }
Another example is array sorting. Here is an example of how you can sort an array in ascending order:
var array = [1, 5, 3, 2, 4] let sortedArray = array.sort() print(sortedArray)
Swift 3 treats this operation as a noun, as it returns a sorted array. The
sort method is now called
sorted :
var array = [1, 5, 3, 2, 4] let sortedArray = array.sorted() print(sortedArray)
Let's sort the array, without using an intermediate constant. In Swift 2, you can call a function like this:
var array = [1, 5, 3, 2, 4] array.sortInPlace() print(array)
You use
sortInPlace () to sort the variable array. Swift 3 treats this method as a verb, since it performs the actual sorting without returning values. It uses only the base word that describes the action. So
sortInPlace () is now called
sort () :
var array = [1, 5, 3, 2, 4] array.sort() print(array)
For more information on the naming convention, you can check out the
API Design Guidelines .
API in Swift
Swift 3 adopts a simple philosophy for its APIs — drop unnecessary words, so if something is superfluous or can be taken out of context, remove it:
- XCPlaygroundPage.currentPage becomes PlaygroundPage.current
- button.setTitle (forState) becomes button.setTitle (for)
- button.addTarget (action, forControlEvents) becomes button.addTarget (action, for)
- NSBundle.mainBundle () becomes Bundle.main ()
- NSData (contentsOfURL) becomes a URL (contentsOf)
- NSJSONSerialization.JSONObjectWithData () becomes JSONSerialization.jsonObject (with)
- UIColor.blueColor () becomes UIColor.blue ()
- UIColor.redColor () becomes UIColor.red ()
Enum
Swift 3 treats the enumeration as a property, so use
lowerCamelCase instead of
upperCamelCase 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 are not using the return value of a function or method. Here is an example:

In the above code, the
printMessage method returns the received message for the caller. However, the return value is not used. This can be a potential problem, so the compiler in Swift 3 will give you a warning.
In this case, if it is not a processed return value. You can suppress the warning by adding
@discardableResult in the method declaration:
override func viewDidLoad() { super.viewDidLoad() printMessage(message: "Hello Swift 3!") } @discardableResult func printMessage(message: String) -> String { let outputMessage = "Output : \(message)" print(outputMessage) return outputMessage }
Conclusion
It's all about Swift 3. The new version of Swift is one of the major releases, which makes the language even better. It contains many fundamental changes that can certainly affect your existing code. I hope that this article will help you better understand the changes, and hopefully will save you some time to transfer your project to Swift.