Many of the libraries have been touched to pull off this effort including-the Swift standard library, all of Cocoa and Cocoa Touch frameworks, Core Graphics, and Grand Central Dispatch. With the release of Swift 3, we can expect changes that reduce the awkwardness of the language's link to Objective-C, exuding way more Swifty-ness. The Swift team has introduced new API guidelines with the intention of giving the language its own character. The result is a huge renaming and refactoring effort that flows throughout the language. Swift 3 has undergone a huge facelift in terms of its interaction with Objective-C and C APIs. The Swift team is aiming to make your development experience feel more like Swift and less like directly dumping Objective-C into your code. Swift is its own language and should have its own feel just like any other programming language. Yet prior versions of Swift were heavily influenced by the need to interact with Objective-C and C APIs.
In this chapter, we will quickly highlight the philosophies for writing good Swift APIs. Afterward, we will spend the remaining chapter on language improvements for referencing and using Objective-C features in Swift 3 and importing code from Objective-C and C to Swift 3. Every language change to Swift 3 is covered by one or more Swift Evolution proposals. As we cover a new feature, I'll also provide the proposal number that documents the rationale behind the change. While knowing the actual rational for a new feature is not critical to your understanding of how to implement its code, I think it is interesting to know the efforts and sometimes debates behind why a particular change was implemented. The Swift Evolution repository contains tons of information on accepted and rejected proposals. If you are a careful observer, you will also see proposals that were accepted for the Swift 3 release but didn't get implemented in time for the release.
Let's start with the proposals for the Swift API Design Guidelines. The Grand Renaming proposals represent, collectively, a very large undertaking and are covered by proposals SE-0005, SE-0006, SE-0086, and SE-0088. Implementing the API guidelines represents the largest change to the language for Swift 3. I couldn't possibly cover every API change resulting in the Grand Renaming proposals in this short book. Thankfully, you don't have to understand every line that changed in the libraries to be productive with Swift 3. You have two fantastic resources that will pay dividends with very little effort on your part. The first resource is the Swift migration tool which converts existing Swift projects to the latest syntax. When you use the Swift migrator, you can convert your Swift 2.2 projects to Swift 3 and receive most of the changes for free. The second extremely valuable resource is the Swift API Guidelines, which were developed to help make your code more Swifty. The Swift API Guidelines are based on the following principles as quoted on https://swift.org/documentation/api-design-guidelines/:
For more details on adopting these guidelines, please refer to the WWDC 2016 lecture on Swift API Guidelines at https://developer.apple.com/videos/play/wwdc2016/403/.
With Swift 3, we get a slew of changes that make working with Objective-C and C APIs more enjoyable. We are going to cover the important changes that will make writing code more productive in Swift 3.
In Objective-C, we can use a type called a selector to reference the name of a method. Swift 2.2 introduced #selector
expressions to remove the error-prone nature of providing string literals as the selector name. In Swift 3, the language builds on #selector expressions by allowing you to reference getter and setter methods. This feature allows us to refer to getter and setter properties of objects. Let's look at an example to see how we could access the setter for one of the properties on our ClassRoom
class:
class ClassRoom: NSObject{ var roomNum: String init(roomNum: String){ self.roomNum = roomNum } } let classRoom = ClassRoom(roomNum: "1-D1") classRoom.perform(#selector(setter: ClassRoom.roomNum), with: "2-D3")
We can now access the setter for the roomNum
using #selector(setter: ClassRoom.roomNum)
or the getter using #selector(getter: ClassRoom.roomNum)
. Once we have our reference, we can use any of the NSObject perform methods available in Objective-C.
You can read the proposal at https://github.com/apple/swift-evolution/blob/master/proposals/0064-property-selectors.md
Similar to selectors, using Objective-C keypaths in Swift 2.2 required us to use string literals. Swift 3 introduces the #keyPath
expressions to improve accuracy by replacing error-prone string literals with objects that can be checked at compile time. Our example below demonstrates how keypaths were done in Swift 2.2 and how referencing keypaths improves with Swift 3.
For Objective-C:
class Employee: NSObject{ var firstName: String var lastName: String var boss: Employee? init(firstName: String, lastName: String, boss: Employee? = nil){ self.firstName = firstName self.lastName = lastName self.boss = boss } } let bossMan = Employee(firstName: "Jack", lastName: "Spark") let rocko = Employee(firstName: "Rocky", lastName: "Jones", boss: bossMan)
For Swift 2.2:
rocko.value(forKeyPath: "Employee.boss.firstName")
For Swift 3:
#keyPath(Employee.boss) // => boss rocko.value(forKeyPath: #keyPath(Employee.boss.firstName)) // => Jack
In our Swift 3 example above, we use the #keyPath
expressions that are compile time checked that allow us to safely access values.
You can read the proposal at https://github.com/apple/swift-evolution/blob/master/proposals/0062-objc-keypaths.md