Swift 3 introduces new API Design Guidelines specifically crafted to the unique character of Swift for clear, concise code. This talk will explore the philosophy behind the Swift API Design Guidelines and their application throughout the Swift Standard Library and the Cocoa and Cocoa Touch APIs. See how this API transformation will affect your Swift code and learn how to ensure a smooth transition to Swift 3. Learn how Swift 3 imports Objective-C APIs and how to expose rich Swift interfaces for existing Objective-C libraries.
Welcome. So, I'm Doug Gregor. I'm here with my colleague Michael Ilseman to talk about design.
Because good design makes us more productive.
And good API design helps us write code that is clear, concise and beautiful in Swift. And that's every bit as true whether you're writing your API for a million other developers or just for yourself inside your own app.
Because good design really does matter.
So, we're going to be talking about the Swift API Design Guidelines today. These are new guidelines we're introducing with Swift 3.
We're going to talk about the philosophy behind these guidelines. Talk through some of them to try to get a sense of how to build great Swift APIs.
Now, then we're going to talk about the Grand Renaming.
Which is what we like to call the application of these guidelines to all of the APIs you use day to day. Swift Standard Library. Cocoa and Cocoa Touch APIs. Now, this Grand Renaming is going to affect a lot of your code.
Pretty much all the code that you've written in Swift 2 is going to change in some sense in Swift 3.
Whooh! Yes! So, we're going to talk through what that means for your code.
And how to deal with it. And starting thinking in Swift 3.
Finally, we're going to talk about some new tools and tricks that we have for mapping C and Objective-C APIs into beautiful Swift APIs. That's a whole lot of what and how. The biggest question you probably have about the guidelines is why? Why, after two years of working with Swift are we changing all the APIs that you work with on a daily basis? And the answer comes down to the character of the language. Because every programing language has its own distinctive character. It has its own syntactic feel.
But it's more than the syntax. It's also the kinds of tradeoffs that that language decides to make. Does it skew toward safety, performance? Do you care about some mathematical terseness or something that is clear and easy to read? You take a look at Swift code, and it's instantly recognizable. And you can see Swift rendering an opinion about certain things here. It uses trailing closures. So the control flow works with your libraries and your APIs nicely.
It has optionals, so you have to consider the possibility of nil everywhere. You can't just ignore that this possibility exists. And so, when you're working with Swift it feels like Swift.
But it's not just the language contributing to it. It's really the APIs you use day in and day out. And these APIs have to meld with the character of the language. So you get a consistent, whole experience of working with beautiful Swift code.
Now, these are some Cocoa and Cocoa Touch APIs.
And these APIs were designed based on the coding guidelines for Cocoa.
You may have read these before. I hope you have.
They espouse clarity and consistency in the design of APIs. And we've been applying these to thousands upon thousands of APIs over more than a decade, all right, to produce the Cocoa and Cocoa Touch platforms. And these wonderful APIs we use.
Now, these guidelines were designed for a different language with a different character.
And so, when you bring all of these APIs that were written for Objective-C into Swift unmodified, they seemed a little bit out of character. They feel a bit not-Swifty.
What's that even mean? Not Swifty? You hear it a lot.
But in essence, this is why two years in to having Swift as a platform that many thousands of developers are using, is the right time to reevaluate.
Because we have experience from a much larger community to understand what works well in Swift code.
And so we set off to design the API Design Guidelines to try to codify what it is to build a Swifty API and help everyone build more consistent, more clear APIs within this language that we love.
Now, in the lower left you see SE-0023. That's the Swift evolution proposal number that contains all of the API Design Guidelines. You'll see these proposal numbers throughout the talk.
Again, you can go look at Swift.org, look up this proposal number to see more information about that particular change to the Swift language.
But for now, let's talk about the guidelines themselves.
The main principles of the Swift API design guidelines are clarity at the point of use. Where your API shows up in someone else's code.
And we love concise code. But the clarity is the most important aspect. It's more important than having brief code.
That said, concise code does happen in Swift. Swift code does tend to be more concise. We can feel it when we look at the language. And we see it in actual metrics when we talk about apps that have been ported into Swift and written in Swift. But that comes from using the right contextual cues.
Let's dive into these principles a little bit more and look at some APIs.
So, we're going to talk about usage first.
So why focus on the use sites? Well, for one, it's just a simple numbers game. You're going to write your API once.
People will look at that API in code, or maybe look at the documentation for it a couple of times.
But the vast majority of times that your API matters, the number of times it's seen, it's going to be in the context of a whole lot of other code.
And when you're in that context, you have all of this extra rich contextual information.
You have the local variables, their names, their types.
You have uses of related APIs. And so the goal of your API isn't to stand up and say, "Hello! I'm here and I have a nice big name." The goal of your API is to fit in with the rest of the code so that the end result is beautiful.
Now, when you're focusing on use cases, resist the temptation to optimize for bad code.
It is absolutely true that someone can go and use names like A and B and C for all the variables. And this code is not clear anymore.
You can't fix this bad code with your API alone.
All you can do is make other code more verbose or less clear.
So focus on proper use cases. Focus on the beautiful code and tune your API for that.
Let's actually look at a specific example here. And so we're going to start with an API that is removing an item from a collection. We're going to start by calling it removeItem.
Sounds good. But I've made my first mistake. This is not a use case. This is just a name in the abstract.
So, let's bring up a use case that I have in mind today.
Don't ask why. He knows. So, remove item ted from the list of friends.
Now, you'll notice that there's actually two things in this use case that are referring to what the argument is. They're trying to describe the argument. There's the word item that's part of our name. And then there's the argument ted which is some local variable with a type.
Of these two, the variable ted is the actual better descriptor of what the argument is. It's in context. As you're reading this call in context, you know what that local variable is. It means something. It has a strong type. So maybe the problem here is really that the word item isn't sufficiently descriptive.
Maybe we'd feel a little bit more comfortable if it were called removeObject.
Well, that's probably not right, because we're probably using value types here anyway. So it's just actively wrong. We could say, hmm, removeElement.
Okay. Collections in Swift use the term element.
But, it's not helping us any.
And moreover, if we were to start writing down different use cases, it might actually become less clear.
Here I want to remove element caffeine from a list of organic compounds.
That's misleading. It's wrong. Caffeine is not an element. It's a compound made up of elements.
So, our attempt at using some innocuous word here to describe the argument has actually led us to less clear use cases.
Okay. So maybe the problem is that we should stop trying to get these innocuous sort of general words in there and we should be really specific.
Remove person ted from the list of friends.
It's a little awkward in English.
I wouldn't say that. I would just say, remove(ted).
But moreover, if I do this, if I try to get really specific for this generic API, well now I expect to be specific everywhere. And now there's one conceptual API of just removing an item from a collection has different names throughout the source base.
That makes it harder to understand. It's harder to recognize that actually we're talking about the same thing in different contexts. So, the Swift API Design Guidelines go a different route. Omit needless words.
If a word is not contributing to the clarity of the use site, don't put it in.
So we can just say, remove(ted) from the list of friends. It reads really nicely.
Now, one of the reasons this works so beautifully in Swift is that it has a strong static type system to make sure that you don't write nonsensical code and again, interpret it in the wrong way. And so the strong static type system is making sure that the argument you passed to remove is an element of the corresponding collection.
If you were to do something truly inadvisable, like for example, try to remove caffeine from your list of friends, you're going to get an error message from the compiler telling you that that doesn't make sense.
So, we've talked about readability of the use sites.
And we've eliminated a bunch of words, which might put you in the mind that what we're looking for is terse code.
That's not true. We want clear code.
But, clear code has to hit the correct point in this sort of spectrum of terseness to verbosity. And if you think about what is verbose code, verbose code is when you have extra information in there that you don't need.
And verbose code actually hurts clarity. Because what is your mind doing as you're reading through this verbose code? It's trying to filter out all of this extra noise, all the things you don't need because they're redundant, to find the actual signal in there.
Now, the other end of the spectrum is also not good. If you have code that is too terse, then you're missing critical information that you need to understand that code.
A sign that this is happening, that you've made things too terse, is when you're reading code and you find yourself jumping to the API documentation all the time because the APIs themselves are insufficiently descriptive.
So we're looking for this sort sweet spot in the middle where you get clear code that is concise. So all of the information you need to understand those APIs and how they work is there in the contextual information.
This is actually a principle of the Swift language itself. So I'm going to put up a bunch of code here.
And in this bunch of code we actually have verbosity that's not needed in Swift. That verbosity is all of these explicit type annotations.
These aren't adding to readability.
You can get a sense of what the types are just by reading the APIs. And indeed, in Swift you probably wouldn't write the code this way. You would probably align that type information and let the static type trebicore do it for you leading to more concise code that you can still read through just as well. Now of course, types are important. And the types are there. And if you need reassurance about what a particular type is, if it'd help your understanding, of course, the answer is just an option click away inside Xcode.
So let's look at another API and try to talk about when a word actually is needed to help describe an argument.
We'll take this little API here that adds a child view at some particular point within some main view.
And so we write out a use case. Always start with the use case. And think about the words that apply to the arguments. So in the first case we have the word child is applying to this view argument that is our first argument.
Is child adding something? Well, we know from the static type system that sidebar is going to be a view of some sort. But this word child is clarifying the role of this parameter in the operation. It's stating that this argument here will become a child. It's establishing hierarchy. That's really important information for understanding what this API does. Now, in the second argument, we have atPoint and then origin. What's origin going to be? Well, it's going to be a CGPoint. This API is going to take CGPoints. And you can't provide anything other than a CGPoint here.
So this word, it's not adding anything. It's just restating information that's already in the strong static type system that will be enforced by the Swift language.
So take it away. You don't need it.
And now notice what the call site looks like here. If we read it out, you add the child sidebar at the origin.
It reads grammatically.
All right? This is one of the principles of this particular API Design Guidelines is that we really want the use sites to read grammatically.
And we had this for our example here of remove(ted) from our list of friends.
Now, let's look at a very related API. So this is removing specifically some element. If we look at, say, the API that removed something in a particular position. Read it out.
Remove position of former friend from the collection. It's not right. This isn't the collection of positions. This is a collection of people.
To actually make this read well we want to say, remove at.
Let's read this out remove at the position of former friend.
Notice how we've clarified the behavior of the API by putting in this first argument label to describe the relationship of the argument to the method.
This brings us to naming and the idea of naming. So, in Swift, a function name is comprised of so-called base name, which here is remove in both of these APIs, as well as all of the argument labels for the arguments. And so these two related APIs, they share the same base name of remove because they're in this method family of operations that remove something from a collection. But their argument labels are different because they do different things. One removes an element by its identity. The other one removes its element based on its position in the sequence.
So slightly different APIs have different names. Now, you can overload based on type information. And if two APIs that share the same compound name.
But you should only do this when the APIs have the same semantics. So it's fine to overload the append name with no argument label here to append a character or a string to some text. Because fundamentally these are the same operation. They're just overloaded on different types for convenience. Now, when you're coming up with first argument labels, again, you want that use case to read grammatically. And that includes the base name of the method as well as the argument label.
So my first API here removeBoxes (withLabel:WWDC).
Notice how that reads well. Now, inside that API we have a prepositional phrase. So it's a little bit of English grammar here. But essentially it's withLabel. And it describes the relationship of the argument to the actual operation of removing boxes. And so when you have one of these prepositional phrases, put it on the first argument label to describe the first argument.
You also use first argument labels if you essentially can't form a grammatical phrase because it would be misleading to have the first argument in there. And so here we have a viewController. And we say dismiss(true). What is that? I can't banish a Boolean constant to anywhere.
And so to make this read grammatically, I need to put an argument label in there.
Dismiss the viewController.
And it's animated. Animated is true. And so this is extra information that's coming along. The first argument label breaks it up so that it reads well and it's clear that what we're dismissing is the actual view controller.
There are a couple of other rules you can read about on Swift.org. But essentially you still will omit first argument labels in some cases. And these are cases where in the API it reads well to just have the argument there, insert michael at the start index of friends.
That reads well. We don't need a first argument label to make it read well, and so we leave it out.
Okay. Let's talk a little bit more about naming before we move on.
So, when you name a method, name it based on its side effects. So, use English verbs, commands, to tell the receiver do something.
So here we might say, okay, we have the friends collection. Reverse it. A viewController, present it. Organic compounds, append to it.
Right? These are actions taken. We name based on the actions taken.
Now, when we have methods whose primary responsibility is just to return some value we use a noun. Describe the thing that is being returned.
And so here we can ask for the background title of a button or the suffix of this friends array.
Now, when you're dealing with value types, it's sometimes the case that you have both a mutating and a non-mutating form of essentially the same operation. And here what we like to call -- we apply what we like to call the ed/ing rule.
And so this follows from English grammar. And essentially you start with the verb form. And so here we have reverse a collection. You're commanding X to reverse itself.
Now, for the more noun-like other form, we use the "ed" rule. So we ask for X reversed. All right? Where we're describing what the result is that we want to get. And that corresponds to the mutating form.
Now, when the "ed" rule doesn't apply, the "ing" rule generally does.
This is usually when we have an argument here. So we have a document directory. We can append a path component to it. That's mutating. We told it to append this.
Now we have the non-mutating form. Give me the document directory appending this particular path component.
So these rules, and many, many more, are described on Swift.org as part of the API Design Guidelines document. Highly recommend that you read them and try to apply them to your own APIs.
But of course, these guidelines, they're not interesting unless they actually are widely applied.
And this is why we set off on the Grand Renaming.
Which is the application of these guidelines to the Swift Standard Library, to the Cocoa and Cocoa Touch APIs as well as targeted improvements to APIs like Core Graphics, Grand Central Dispatch. They're used all the time to give them these Swifty makeovers to be beautiful in Swift.
I talked a little bit about the scale of the Grand Renaming. So, this is a little screen shot of a small Swift app called Lister we've been shipping for a couple years. It's one of the sample applications when it's being migrated from Swift 2 to Swift 3.
You can notice there's a whole lot of .swift files on the left.
Basically every Swift file in the entire project is changed by the transition from Swift 2 to Swift 3.
And if you're looking at some of the details in the middle and the right panes here, you probably noticed that all of these Cocoa API names have changed.
Okay? So, there's a lot of change here. We'll talk about that. But really what's interesting is that these Cocoa APIs you may have been using for a very long time, the APIs are the same, but now a given API has two different names.
Has one name that's appropriate for Objective-C and one name that's appropriate for Swift. As a Swift programmer, most of the time you don't need to care.
You can entirely work within the Swift names. Use your generated interfaces, the documentation, everything will show you the Swift names. And that's all you'll deal with.
However, there are times when you're interacting with the system where you actually do need the Objective-C name. For example, if you're wiring up target action.
And so, here we actually need to provide a selector to target action. And we have this string literal.
What do we write here? I don't know. You can look at the generated interface.
Maybe ask your Swift compiler friends on Twitter or something. You can come up with the answer. That's fine.
But, please don't do this.
Because this is a really, really weak link between this string literal, which is super easy to mistype, and the method above that you actually meant to call.
This is why in Swift 2.2 we introduced #selector.
#selector is a very simple thing. It's an expression. It takes in the name of a Swift method and produces the Objective-C name for that method. You don't have to care what that Objective-C name is. The compiler will get it right. And the great thing about this, of course, is that Swift makes sure that that method exists. Makes sure it's exposed to Objective-C, and computes the correct name. And of course, this is safe against refactoring. Works with code completion. So it's a much nicer development experience. That means you don't have to worry about the Objective-C names.
In Swift 3 we've extended this so you can also refer to getters and setters of properties. So we round out the set of Objective-C method names you can actually compute. So this is very easy to use. You just pass in the argument label setter or getter to get the setter or the getter respectively. And then refer to an Objective-C property.
And of course, the compiler will validate that that property exists, that it's exposed to Objective-C and get the right Objective-C name for it.
Now, selectors aren't the only sort of stringly type thing we have when talking about Objective-C method names.
We also have Key Paths, which are notoriously hard to get right when writing these things as string literals with no validation.
And so, in Swift 3 we're also introducing #keyPath.
#keyPath does exactly what you'd expect. You get to refer to a dotted sequence of property accesses. Compiler validates that these are actually Objective-C properties, gets the right names. And then produces the string that we pass down into the frameworks. And so between #selector and #keyPath, you can essentially not worry about the Objective-C names.
You just write everything in terms of the Swift names and you stay in that set of names. You don't have to straddle the boundary.
Now, there are cases where you do need to think about what the Objective-C names are. You may have a mixed project with Objective-C code in it that needs to refer to the names in your Swift code.
And names like this handleDragWithSender for just don't feel right when they're in Objective-C.
So for these cases, you can use the @objc attribute. And in parentheses put the exact Objective-C name that you want.
And that will be reflected in your generated headers and all of the metadata and everything else so you get specific control over the Objective-C names, but no other part of your Swift code actually has to care about this. And of course, this @objc with a name works for properties, it works for methods, classes, protocols. Anything that can be exposed to Objective-C from Swift, you can control the name here.
So you get nice Objective-C APIs for your Swift code.
Okay. There's a lot of change coming with Swift 3.
The Swift language itself abstracts away the need to worry about the Objective-C names, and yet it gives you the control you need for those times when you do care about the Objective-C names.
The tools are here to help you.
So the Swift 3 migrator is going to Swift 2 code and migrate it to the Swift 3 names and the Swift 3 syntax. It's a lot of change.
But these tools will help you get over the hump and get working with Swift 3.
Now, the Swift 3 migrator is a great tool.
But it can't migrate your muscle memory.
Certainly can't migrate all that code you copy and paste from stack overflow.
So, the Swift compiler's also here to help you.
The Swift compiler, it knows the Swift 2 names of all of these APIs as well as the Swift 3 names. So if you write or paste in some code from Swift 2, it'll recognize the old API names and give you diagnostics with Fix-its to update your code so you can get moving faster.
Additionally, we've put in near miss detection when you're implementing optional protocol methods. And so this is great when you're implementing a delegate. You make some minor mistake in the name of that delegate method you want to implement. Now you'll get a warning with a Fix-it to fix up the names so you can be sure that your method will be called properly. All right.
Now I'd like to turn things over to my colleague Michael, who's going to talk about the mapping of C and Objective-C APIs into Swift.
So that's a lot about Swift. But what if you're an Objective-C developer or are working with a mixed project? All of your Objective-C APIs are available in Swift. They always have been. But as Doug explained, they were designed for a different language. They are increasingly starting to feel a little bit foreign in Swift.
So today I'm going to show you how you can take control of the situation and give your Swift users the APIs they deserve.
I'm going to start with a couple Objective-C APIs as they were imported into Swift 2.
Here we have two methods; saveToURL, forSaveOperation and revertToContentsOfURL.
But these don't really express the API Design Guidelines that Doug outlined. There's a lot of redundant type information.
We're not making effective use of the first parameter labels, first argument labels. So I'm going to start with what you get for free automatically in the Swift 3 compiler. Swift 3 has improvements to how Objective-C APIs are imported.
The Swift compiler will inspect method names and use grammatical cues in order to infer first parameter labels.
The Swift compiler will inspect names in order to eliminate redundant type information.
The compiler can even infer default arguments for common Objective-C idioms such as completion handlers.
Or option sets.
And also, there are new value types such as URL that bridge to NSURL. So when we import, we just import it directly.
To find out more about these value types, visit, What's New in Foundation for Swift later today.
So, automatic inference is great and all, but fundamentally it's driven by heuristics. The compiler, it can't read your mind. It doesn't know your intent.
And every now and then you want to specify your own name. So we've extended NS Swift Name. Now, NS Swift Name has been around since Swift 2. But in Swift 3 we support full compound naming.
A compound name is a base name plus the argument labels. So in this case, we have two methods.
They're performing semantically very similar operations. But they differ basically in how they treat their argument. And so we import them with the same base name constraints, but we say we want it equal to this anchor or greater than or equal to this anchor.
Now, method names will get you a long way towards a Swifty API, but this doesn't quite go far enough.
Here I have some simple code that's creating a standard Gregorian calendar.
But if you look at this, this doesn't really feel very Swifty, especially NSCalendarIdentifierGregorian, which is a plain string global variable. Plain string global variables, that's not really how we do Swift. This is what we jokingly refer to as stringly-typed API.
And the fact that this API takes a string, that kind of allows simple errors. And yes, I know this bug is shallow and a developer would catch it right away.
But the fact that a user of this API has to remember what it is and it's not a valid string to use here, that's an unnecessary cognitive burden.
So, why is this API like this? Well, we all know why this API is like this. It came from Objective-C.
But the fact that this API came from Objective-C, that's an implementation detail. And that implementation detail is leaking out.
And at Apple, we're not big fans of leaks. To figure out what's going wrong, let's see how this Objective-C API is mapping into Swift. Our global variable comes in as a global variable, of course.
But other than the name of this global variable, nothing really tells you that this a very specific string meant for a very specific API.
Now, we could try adding a typedef to try and hint at our intent. But a typedef, it's just a type alias. It's a new name for an old type.
And so that doesn't really fix the problem here.
So, how will this API look if we were going to design this fresh in Swift 3? Well, we'd probably make a new wrapper type around string to get some strong typing. And these global variables, well, those would instead be static properties.
So in Swift 3 we introduced a new attribute just for this use case. You can access this attribute through NS Extensible String Enum when you wish to tell the Swift compiler to make a new wrapper type around your string.
You can just add this to your typedef.
And the importer will create you the new type around this. And any global variables of this type will get imported automatically as static properties of this type.
Now, we chose a struct here because this is extensible. That is, other modules may want to define their own. And if they do, they will also be imported as static properties on an extension of this struct.
Now, behind the scenes the Swift compiler will map this directly to the underlying stored value, meaning that there's no extra overhead or boxing or intermediaries involved.
So, let's focus on the use site. Because good API design is always focused on the use site.
Before and after. And because the type context is clearer, we can even just say .gregorian.
I'll kick it off by starting myself next time. Also, in Swift 3 NSCalendar, it's now just known as Calendar. This is a little fix up. So, we have method names and we have types. What else do we have? Well, we have an elephant.
That is, we have an elephant in the room.
And we've been pretending not to notice it. But it's always been there.
And it's C.
Now, with Objective-C, the APIs were already object-oriented, so when we import them we just change a few strings, add a few types. It's relatively straightforward. But what about C? I'm going to focus on Core Graphics. Now, Core Graphics is a very popular API that's used by pretty much every Swift app out there. It is a powerful API. But it looks and it feels like C.
Let's start with some code. I have two functions here. The first one transforms a -- takes a transform and rotates it about a given offset.
And the second function traces a path in red. Now, neither of these functions are too complicated, and the details don't matter. But I just want to look at how does this look? How does this feel? Go ahead and take a moment.
So, if you notice, this code is completely filled with global variables and global functions. And we don't really like global functions, of course.
Or global variables, of course.
So, how could we take an API like this and make it look Swifty? How can we make it feel Swifty? Well, for that, we revisit our friend NS Swift Name. You can use NS Swift Name in order to import globals as members of types.
Let me start with global variables to show you what I mean.
Here at the top I have this C definition. Below that the generated Swift interface. And underneath that the Swift use site. And we will be focusing on the Swift use site and improving the Swift use site.
So we add NS Swift Name and we use typename.membername in order to tell the Swift compiler that kCGColorWhite should be imported as the static property white on CGColor. And of course, the Swift use site can now use the properly nested property.
And of course, if the type context is clear, users can even omit the CGColor.
Now Core Graphics has a lot of different global functions to create all different kinds of CG Affine Transforms. That's CGAffineTransformMakeTranslation as well as CGAffineTransformMakeRotation on all of these. But in Swift we prefer Initializer. So we use TypeName.Init and provide argument labels in order to tell the Swift compiler that this should really just be an initializer. And we use argument labels in order to clarify the roles of the parameter.
You can also import as an instance member. Use the special argument label self in order to tell the Swift compiler what argument to plug the reference to self into.
And so now CGContextFillPath is now just the method fill path. And of course, the Swift use site, it just calls it like a method.
And the compiler will take what's on the left of the dot and plug it into the appropriate parameter position as denoted by the special argument label self.
We can get more complicated. You can prefix a Swift name with getter or setter in order to tell the compiler to import this function as a computed property getter or setter.
Here ArtistGetName, ArtistSetName are now just the getters and setters for the computed property Artist.
Let's focus in the use site because good API design is always focused on the use site. Before, we would use a global function to remember the former name of an artist and a different global function to set a new name.
But now, our users can use the computed property directly.
In all cases, this is a zero cost overhead. That is, when the compiler sees myArtist.Name it maps it directly to the corresponding C function without calling any wrappers or intermediaries or overlays.
You can also use NS Swift Name in order to nest types. Remember earlier when we created a new calendar identifier type? Well, you can use typeName.
-- well member name -- nest a type name in order to nest a type. So in this case we get Calendar.Identifier.
Now, we love the new NS Swift Name.
We love it so much that we went absolutely, completely bananas.
Don't clap for this.
And we applied it to over 600 APIs in Core Graphics alone, 600.
Now you can clap.
That's a lot of bananas.
So, let's revisit the code from before. Before, our global variable, which is painfully global, is now a member. And because the type context is clearer, we can even omit the type name. Our global functions are now methods.
Actually, now that I look at this, I think this code can even simpler. We don't need that extra variable result.
And so now this reads -- And so now this reads nice, natural and Swifty. We take a transform. We translate it. We rotate it. And we translate it back. Very straightforward.
CGColorCreateGenericRGB as well as all of the other many, many different ways to create colors, these are now initializers with argument labels. And of course -- hold your applause -- and of course CGContextAddPath, ContextPath and all of the other crazy redundant stuff, they're now methods.
We hope you enjoy these new APIs. So, to summarize, first we presented the new API Design Guidelines in Swift.
Good API design is always focused on the use site. Second, we looked at the Grand Renaming. This is also known as, "Oh, no! Everything's different." But don't panic. It's okay. The names are better. The code is clearer. And you have the tools to migrate. And last, we looked at the new functionality in the Swift compiler so that you can have your own Great Renaming.
For more information, visit the page for this site at developer.apple.com and check out Swift.org, the homepage of the open source Swift project where you can see all of the Swift evolution. I also showed you Core Graphics. But Grand Central Dispatch has had its own Great Renaming using many of these same techniques I presented today. So, Friday, check out concurrent programming with Grand Central Dispatch in Swift 3.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.