Bummer! This is just a preview. You need to be signed in with a Pro account to view the entire video.
Start a free Basic trial
to watch this video
Learn how to migrate your projects to Swift 3.
-
0:00
Hi, I'm Pasan, an iOS instructor here at Treehouse.
-
0:04
And in this workshop, we're going to go over migrating to Swift 3 and Xcode 8.
-
0:08
Over the course of this workshop, we're going to talk about
-
0:11
why you should migrate, how you should migrate your codebase over.
-
0:16
And then spend some time looking at the major and minor changes to Swift 3.
-
0:22
Let's start with why you should consider migrating.
-
0:25
The first thing to note is that Swift is still not ABI-stable.
-
0:30
This means that application binaries created with previous versions of Swift
-
0:35
are not compatible with the current compiler.
-
0:38
ABI stability was originally a goal of the 3.0 release.
-
0:42
So it's important to be aware that it was pushed.
-
0:45
We've now been promised ABI stability in the 4.0 release.
-
0:50
There are good reasons to migrate to Swift 3 as well.
-
0:53
Swift 3 brings a much-needed consistency in API design across the language.
-
0:58
The changes are vast, which is where most of the migration pain will be apparent.
-
1:04
But the guidelines are clearly defined and give Swift a character of its own.
-
1:09
With Swift 1 and 2,
-
1:10
we've mostly been using a variation of Cocoa's design guidelines.
-
1:15
And it felt clunky in a lot of places.
-
1:18
With the goal of cross-platform swift, Cocoa conventions make even less sense.
-
1:23
So the new guidelines aim to resolve that.
-
1:26
We'll go over some of these high-level changes.
-
1:30
The new API guidelines have been applied to Objective-C APIs imported into Swift.
-
1:37
And along with better use of Swift's features,
-
1:40
it is a much nicer experience using Cocoa Touch classes in Swift.
-
1:45
We'll be taking a look at some of these examples as well.
-
1:49
A final reason for moving to Swift 3 is better tooling and language support.
-
1:55
Xcode 8 includes several new and improved features,
-
1:59
like a runtime issue report generator, a brand new memory debugger,
-
2:04
a thread sanitizer to spot race conditions, and an improved view debugger.
-
2:10
If your codebase is in Swift,
-
2:12
moving to Xcode 8 means making a decision on the language version.
-
2:18
So perhaps you know that you want to migrate to Swift 3, but
-
2:21
you're unsure about when you should do this.
-
2:24
How urgent is the need?
-
2:27
Swift 1 to Swift 2 was pretty urgent.
-
2:30
You could not use Xcode 7 unless you migrated your codebase, and
-
2:34
this was quite painful.
-
2:36
It meant choosing between migrating your codebase,
-
2:39
versus improving your app for users by adding new functionality and features.
-
2:44
With Xcode 8, Apple is a bit more forgiving, thankfully.
-
2:49
Xcode 8 supports both Swift 2.3 and Swift 3.0.
-
2:53
It's important to note, though, that we don't know how long that will last.
-
2:58
A future minor version of Xcode 8 may remove this functionality and
-
3:02
only support 3.0.
-
3:04
It really is intended to just give us more time to migrate over,
-
3:08
because the changes are pretty vast.
-
3:10
So while you do have the ability to use Xcode 8 with a codebase in Swift 2.3,
-
3:16
I would recommend getting started as soon as possible.
-
3:20
I've heard everything, ranging from Xcode will support 2 versions until Xcode 9,
-
3:26
to the next minor version will only support 3.0 and up.
-
3:31
Even if you decide that you are going to stick with Swift 2.3 for now,
-
3:34
your hand might be forced.
-
3:37
Most third-party libraries are well underway with Swift 3 versions and
-
3:42
have frozen their 2.3 versions.
-
3:46
You can expect bugfixes, but not much else.
-
3:49
Given the lack of ABI stability, if you use several dependencies,
-
3:53
the burden now falls on you to maintain a fork for as long as you need to.
-
3:58
While there's no urgency to this, another good reason to migrate is to take
-
4:03
advantage of the improved safety offered by improved Objective-C API in Swift 3.
-
4:10
Some of the improvements to the SDK in iOS 10 are available only through Swift 3.
-
4:16
One of my new favorite features is the usage of generics in Core Data API,
-
4:20
something we'll look at in later slides.
-
4:24
This, for example, is only available in Swift 3 for those of you writing Swift.
-
4:30
Let's say you've decided to migrate.
-
4:32
What are you getting yourself into?
-
4:34
Over the next few minutes, let's go over some of the major changes to the language.
-
4:39
This will be a quick overview.
-
4:41
The scope of some of the changes are extensive.
-
4:44
But I've provided links to resources at the end of this deck for you to check out.
-
4:48
We'll start by exploring the new API Design Guidelines,
-
4:52
particularly those that define the new naming conventions.
-
4:55
After that, we'll see how these guidelines have been imported to Objective-C API and
-
5:00
why they're much nicer to use in Swift 3.
-
5:03
Swift 3 also includes new types that makes both the cross-language and
-
5:08
the cross-platform development experience easier, and we'll touch on this.
-
5:13
Finally, we'll take a look at few of the minor changes and some strategies for
-
5:16
migrating.
-
5:18
The most apparent changes are those defined in the new API Design Guidelines.
-
5:23
Not only do they require you to think differently from naming
-
5:27
conventions established by decades of Cocoa and Cocoa Touch development.
-
5:31
But the application of these guidelines mean that usage of familiar API is
-
5:36
different now.
-
5:37
And this affects how our codebases are designed.
-
5:42
Let's start with the fundamentals.
-
5:44
These are overall guidelines that should help you understand the point of view of
-
5:48
the Swift core team.
-
5:49
And thereby, help you get in the mindframe of redesigning your own API.
-
5:54
Before we proceed, as we go through these slides, you'll notice in the bottom
-
5:59
right-hand corner a link in the format SE, followed by a number.
-
6:04
This is a link to the swift-evolution post on GitHub that provides an excellent,
-
6:10
in-depth summary of the changes we're talking about.
-
6:13
If you're interested in learning more about each change,
-
6:16
that's where you should go.
-
6:18
All code should be written so that it reads well.
-
6:21
But Swift 3 approaches this from a slightly different perspective than we
-
6:26
might be used to.
-
6:27
Objective-C classes have both a header and an implementation file.
-
6:32
API design in Objective-C was focused on making methods and
-
6:36
variables descriptive and informative through a header file.
-
6:40
We're all familiar with Objective-C's verbosity.
-
6:43
And this provided for a great deal of clarity and intent.
-
6:47
In Swift 3, the focus has shifted to clarity at the point of use.
-
6:52
We want to design API that is readable, concise, and clear when our methods and
-
6:58
functions are called, rather than when we look at a class' interface.
-
7:03
When Swift was released, the pendulum swung from one end, with Objective-C-style
-
7:08
verbosity, to the other end, where developers often focused on brevity.
-
7:14
Swift 3 makes it clear that brevity should not be a goal in API design.
-
7:19
Instead, it should be a side effect of focusing on clear API
-
7:24
that uses Swift's language features like the type system.
-
7:27
Essentially, at no point should you be focused
-
7:30
on writing the smallest amount of code.
-
7:33
Swift 3 also uses a variation of CommonMark, a dialect of Markdown,
-
7:38
to provide a consistent format around documentation and doc comments.
-
7:44
Since the focus on API design is at the point of use,
-
7:48
Swift 3 relies on documentation comments and
-
7:50
Xcode IDE features to provide full method descriptions in any related documentation.
-
7:57
As I mentioned, these API Design Guidelines are pretty vast.
-
8:01
So let's break it down and look at some of the new naming changes, so
-
8:04
you have an idea of what you're getting into.
-
8:08
One of the major goals of Swift 3 is to prevent ambiguity at the call site and
-
8:12
to promote clear usage.
-
8:15
This means including all the words necessary in the method signature
-
8:18
that are needed to convey intent.
-
8:20
Now, this sounds like Objective-C, but there are further restrictions.
-
8:25
So here, we have an example of API that would be deemed
-
8:28
ambiguous under the new guidelines.
-
8:31
We have a remove method that removes an element at an index position and
-
8:36
returns it.
-
8:37
At the point of definition in the class' interface, this reads well and
-
8:42
it's obvious what the method does.
-
8:44
However, remember that with Swift 3, the focus is at the call site.
-
8:48
At the call site here, it's unclear whether we're
-
8:51
removing a particular element, an element equal to some object,
-
8:55
or whether we're actually fiddling with the index.
-
9:00
Here is the same method formatted for Swift 3.
-
9:03
Swift 3 makes a departure from Cocoa and
-
9:06
Objective-C conventions when it comes to argument labeling.
-
9:10
Consistent label behavior has been established across all parameters,
-
9:14
including the first label.
-
9:16
Whereas in Swift 2 and
-
9:17
prior, the first argument label was omitted by default to match Cocoa.
-
9:22
Here, we've given the method an external argument,
-
9:25
at, to clearly indicate we're removing at a particular index.
-
9:30
We've also defined a typealias to provide increased clarity around the index value.
-
9:37
That first rule of including all the words made it sound like we were striving for
-
9:41
Objective-C's verbosity.
-
9:43
But that's not actually the case, because our second rule is to omit needless words.
-
9:49
That is, redundancy should not be a goal.
-
9:53
Here's a simple example.
-
9:55
Here, we have the signature for
-
9:56
a class method on NSLayoutConstraint that activates an array of constraints.
-
10:02
This would be considered poor API design in Swift 3, why?
-
10:07
We have a lot of redundant information here.
-
10:10
It's clear, from both the type on the argument as well as the label,
-
10:14
that we're activating constraints.
-
10:16
Yet we're being redundant by specifying this in the base method name.
-
10:21
This isn't as bad in Swift 2, because that argument label would be omitted.
-
10:25
But in Swift 3, that's a lot of times that we're saying constraint.
-
10:29
One in the class name, one in the base method name, one in the argument label,
-
10:34
and the final time through the type.
-
10:37
Here is the same method in Swift 3.
-
10:39
The method name is now simply activate.
-
10:43
We're relying on a Swift feature,
-
10:45
the strong type system, to clarify what it is we're activating.
-
10:50
Because the type is sufficient enough, anything else is redundant.
-
10:54
So we've intentionally omitted the external argument label as well.
-
10:58
The final method at its call site reads as a grammatical English phrase,
-
11:03
which is one of Swift's goals.
-
11:05
NSLayoutConstraint.activate(constraints).
-
11:10
Speaking of English phrases,
-
11:12
there are several rules governing naming conventions.
-
11:15
I highly recommend you take the time to go through the guidelines carefully.
-
11:20
Both in the proposal linked below and
-
11:23
the official guidelines page linked at the end of this deck.
-
11:28
New naming conventions affect our codebase in two ways.
-
11:32
One in the code we write, and
-
11:34
second, the code that we call from Cocoa Touch frameworks.
-
11:38
The application of new guidelines affects changes to both how Objective-C,
-
11:43
and even C methods and functions, are imported into Swift.
-
11:47
As well as the usage of these methods by making use of Swift-only features.
-
11:53
One of the more obvious changes that makes for a great example is Core Data API.
-
11:58
In Swift 3, NSFetchRequest is a generic type
-
12:02
with a type parameter that conforms to a new protocol, NSFetchRequestResult.
-
12:09
This means that given an NSManagedObject subclass Foo,
-
12:13
we can create a FetchRequest for Foo like this.
-
12:16
No more stringly-typed entity names.
-
12:20
Furthermore, if we look at the signature for
-
12:22
the fetch method, you'll notice that the return type is not AnyObject,
-
12:26
as it was in Swift 2, but the type of the generic parameter.
-
12:31
This means that if we call fetch on a context and provide a FetchRequest, we're
-
12:36
guaranteed to get an array of the type back, rather than an array of any object.
-
12:42
You'll notice, throughout this example as well,
-
12:44
that the new guidelines have been applied to existing Objective-C API for
-
12:48
a more consistent naming experience in Swift.
-
12:52
Speaking of Any and AnyObject,
-
12:54
Swift now imports any API typed with ID as Any, rather than AnyObject.
-
13:01
For example, here's a bit of code from the NSFetchedResultsController delegate
-
13:06
protocol, sticking with our Core Data example.
-
13:09
Notice that the object changed over here as an argument type of AnyObject.
-
13:16
In Swift 3, this comes in as Any now.
-
13:20
The motivation behind this change is to keep Swiss value semantics consistent
-
13:24
when importing Objective-C API.
-
13:28
It's worth reading the entire proposal to understand the scope of this change.
-
13:33
The reason I bring this up is because the migrator doesn't always play nice.
-
13:37
So it's important to be aware of bugs in Xcode that can affect you.
-
13:41
So here's my experience.
-
13:43
I recently migrated a project from Swift 2 to Swift 3.
-
13:45
The migrator seemingly did its job.
-
13:49
But there were a few cases where it did not convert the types of such
-
13:54
imported API from AnyObject to Any.
-
13:57
There were no compiler errors raised by the inability to convert these methods.
-
14:02
But because the signature of this particular delegate method did not match
-
14:07
the signature of the one in the protocol, my delegate method was never being called.
-
14:12
What's more surprising is that there was no compiler error informing me that I was
-
14:16
not fulfilling the delegate protocol contract.
-
14:20
Took me a while to track that down.
-
14:23
In much the same way, in sets and dictionaries, NSObject and
-
14:28
AnyObject are now imported as AnyHashable and Any.
-
14:32
This is important to know, because if you are writing Objective-C code or
-
14:37
are a library author, there are new Objective-C features to control and
-
14:41
adapt this importing.
-
14:44
All these features make the experience of working with both languages much better.
-
14:48
And should hint at a future where neither language is really
-
14:51
preferred over the other, but up to the developer.
-
14:55
There are several changes around this goal, including one of my favorites,
-
14:59
proposal number 33, which imports Objective-C constants as
-
15:04
Swift types like enums.
-
15:08
One of the more interesting changes to Swift is the overhaul of the standard
-
15:11
library.
-
15:13
This was motivated both by mutability concerns and
-
15:16
the lack of foundation types in a cross-platform experience.
-
15:20
NSDate now has a Swift equivalent, Date, URL for NSURL, and so on.
-
15:27
These new types are value types and play well with Swift's mutability semantics.
-
15:32
You might run into minor errors during a migration process, where you were
-
15:37
previously mutating a reference type that has now been bridged to a value type.
-
15:41
But this is a good thing, in my opinion.
-
15:43
You're aware of this error up front.
-
15:45
Note that you are not required to only use the new foundation types, but
-
15:49
have access to the legacy Objective-C types as well.
-
15:53
These types also play well with each other and
-
15:55
are automatically bridged as you move from one language to the other.
-
16:01
Libdispatch is also improved in Swift 3.
-
16:04
Here, we see an example of libdispatch in Swift 2.
-
16:08
In the first snippet,
-
16:09
we call dispatch_queue_create to create a custom queue.
-
16:12
And then call dispatch_async and pass in the queue to execute some arbitrary code.
-
16:18
In the second snippet, we're executing some arbitrary code on the main_queue.
-
16:23
In both these situations, the libdispatch library is imported as is.
-
16:28
And the C API seems completely out of place.
-
16:33
In Swift 3, the API surface has been transformed to feel much more natural.
-
16:38
We now have a DispatchQueue type with class properties
-
16:42
to return various common queues.
-
16:44
We also have instance methods that dispatch our code, either synchronously or
-
16:49
asynchronously.
-
16:50
While a true concurrency model is still a ways off in Swift 4,
-
16:54
this is a much better experience.
-
16:58
Let's look at one last change that makes a pretty big impact when migrating.
-
17:03
Swift 3 brings some new access control keywords and
-
17:06
changes the meaning of existing ones.
-
17:09
One of the new access control keywords is fileprivate.
-
17:13
A fileprivate variable is only visible inside the file.
-
17:17
This means that you can use fileprivate inside a particular Swift file and
-
17:21
across any extensions of the type in that file.
-
17:26
But this is what private used to mean.
-
17:28
Well, private now means private to the current scope.
-
17:32
A variable defined as private cannot be accessed in an extension of the type.
-
17:38
A second proposal, 117,
-
17:40
introduces a new keyword, open, and changes the meaning of public.
-
17:46
In Swift 2, declaring a class or variable as public
-
17:50
meant that external modules could use the class and override it.
-
17:54
In Swift 3,
-
17:56
public now means that external modules can use the class, but cannot override it.
-
18:01
Instead, a new keyword has been introduced, open.
-
18:04
That means a class can be used and overridden by an external module.
-
18:09
These newer keywords will certainly impact your codebase as you migrate to Swift 3.
-
18:15
Many of the variables, constants, and functions marked as private, but
-
18:19
used in extensions, will now return compiler errors.
-
18:22
Essentially, there's a bit of cleanup to do.
-
18:26
As you can see, there are lots of changes you will have to make,
-
18:29
both to your code and the code you call.
-
18:32
And we've only covered some of the major changes.
-
18:35
There are several minor changes as well that'll undoubtedly impact you.
-
18:39
So how should you go about it?
-
18:42
The first thing is, you should ensure that you have decent test coverage.
-
18:47
You'll want to know that the codebase behaves in the same way after migration.
-
18:51
So make sure you have benchmarks that inform you as such.
-
18:55
Next, start your migration by using the built-in migrator.
-
18:59
It's far from perfect, but
-
19:01
it will take care of most of the renaming of API from frameworks.
-
19:06
But beware,
-
19:06
of course, there might be some edge cases that you'll have to take care of.
-
19:11
Set aside a decent amount of time.
-
19:14
The scope of changes is pretty vast.
-
19:16
It's more painful going from Swift 2 to Swift 3, than Swift 1 to Swift 2.
-
19:20
And you have to do it all at once.
-
19:23
So don't try to get this done while hitting other deadlines as well.
-
19:28
Finally, and
-
19:29
probably a bit more painful, is to figure out a strategy for all your dependencies.
-
19:34
Most third-party libraries have Swift 3 branches that you can already pull in.
-
19:38
But the situation may vary on a case-by-case basis.
-
19:43
While you're certainly not in a great rush to get this done,
-
19:46
remember that any Swift 2 code written right now is technical debt.
-
19:50
So you want to try and get this done as soon as possible.
-
19:53
I've included a few resources so you can read up on the scope of changes.
You need to sign up for Treehouse in order to download course files.
Sign up