[ Silence ]
[ Applause ]
So I'm Doug Gregor.
I'm an engineer on the Swift Compiler Team, and we're here to talk about Swift Interoperabiity.
We're going to talk about a couple of different things here.
So, of course, Swift is a new language for Cocoa and Cocoa Touch development.
Now, Cocoa's not written in Swift.
It's written in Objective-C, a language you've been using for years and that all of your apps are written in.
So, interoperability between these two very different programming languages is absolutely critical.
So we're going to talk about how that interoperating works at the language level.
We're going to hit a number of different topics today.
We're going to talk about working with Cocoa, seeing how the Cocoa APIs or Objective-C APIs look and feel in Swift and how to work with them, as well as working with some more Swift concepts like dealing with AnyObject and doing dynamic checks on your types.
Then we're going to talk about bridging of the core Cocoa datatypes and NSArray, NSDictionary, NSString into their Swift-native equivalents.
Then we'll move on to subclassing, so writing Swift classes that subclass from Objective-C and how they're mapped back into Objective-C so that you can use these two languages together.
And, finally, we're going to talk about Core Foundation and Core Graphics, and this general notion of CF Interoperability within the Swift programming language.
Let's get started talking about working with Cocoa.
So Swift provides seamless access to Objective-C APIs through the Objective-C Module System we introduced last year.
So you can pull your Objective-C APIs whether they be from Cocoa or your own into Swift and use them.
And then Swift maps those Objective-C APIs into the Swift syntax.
This covers both the objective parts of Objective-C - the classes, protocols, methods, and so on, as well as the lower level C things like functions, enumerations, structs, pointers.
So you have access to all of your Objective-C APIs.
Now when you look at one of these Objective-C APIs in Swift, it's going to be different from Objective-C.
There are inherent syntactic differences between these two language, of course.
Swift also has some modern features that we use when expressing those Objective-C APIs in Swift that will make it look a little bit different, as well as the bridging of core Cocoa types that I mentioned earlier.
Now, despite all of these differences that you see when looking at the APIs, it's still Cocoa, it's still Cocoa Touch.
And the same conventions and idioms still apply, so what you know of Cocoa works in Swift.
It's just a different programming language for the same great platform, the same great frameworks.
So we're going to walk through part of something we know and love, and that's the UIDocument class.
Here's a tiny slice of it in Objective-C.
We're going to walk through how and why that maps into Swift.
First thing, something simple, a property: fileModificationDate.
It is an NSDate!.
This comes into Swift as a property.
It's the var keyword.
The NSDate class, of course just comes into Swift.
Nothing interesting there except for this little exclamation point that you may have noticed.
Now that exclamation point is an Implicitly Unwrapped Optional.
What does that mean?
Well, let's look at Swift in Objective-C.
They're different languages with some different ideas in them.
So in Swift, when you have a value of class type, so I have an NSDate!
That can never be nil.
So a very strong constraint.
And it makes life a bit simpler when you know that thing is not nil.
Now, when you want to deal with nil, you have an NSDate!
that could be nil, you use an optional type, and optional types are covered extensively in the "Intermediate Swift" talk.
We're going to cover them a little bit more now.
That's the Swift side of things.
What about Objective-C?
Well, it does not have the notion of a never "never-nil" pointer like we have in Swift.
And so we have a little impedance mismatch here.
The Objective-C APIs don't have the notion of this is not nil, but we need to bring them into Swift.
And so, we have the implicitly unwrapped optional with the exclamation point here.
And this gives us a nice balance.
It means that we can express the notion of nil and you can test it against nil to do those checks.
However, you can also just directly access properties or directly call a method on it, or you can convert it down to NSNil, and we'll unwrap that optional object automatically for you doing the checking.
So it's a fairly syntactically lightweight way of dealing with nil in a language where nil is a much more explicit entity like in Swift.
Let's look at another property.
So here we have the fileType property that's in NSString.
This is going to come into Swift as a native Swift string.
Now, again, we have the implicitly unwrapped optional here so that nil can be passed through since NSString doesn't have a notion of nil inside it.
And there's a number of Objective-C types that get mapped slightly differently into Swift.
So there's some very, very fundamental types like BOOL and NSInteger that map into the Bool and Int types within Swift.
So we're working with all the Swift types.
There's id and Class, which we're very familiar with in Objective-C.
These map over to AnyObject!
and AnyClass!, something we're going to talk about in a couple of minutes.
And we also have the core Cocoa types that are bridged, like NSString and NSArray, mapping to their Swift-native equivalents.
Again, we'll talk about that later in this talk.
Let's take a look at methods.
There's an Objective-C method fileNameExtensionForType, saveOperation.
It comes into Swift here as, again, a method.
Now, one important thing to know here is that all of the selector pieces from the Objective-C method are here in the method's signature in Swift.
The first selector piece has become the so-called base name of the method.
The second selector piece, SaveOperation, has become a label on the second argument.
A really important thing here is that these labels and their order are enforced at the call site.
So, you must call it as fileNameExtensionForType, saveOperation, just like you do in Cocoa with the exact same ordering, so to preserve that nice readability from Cocoa that we all know and love.
Now the other thing to note here is the consistency here on the Swift side.
All of the names and the colons and the parentheses and the commas are in exactly the same places in the declaration of the method in the middle and in the call site of the method at the bottom.
So the kind of consistency we like out of building a new language.
Let's look at a little bit more complicated method here where we have some blocks going on, some more interesting things, and map that into Swift.
And here there are two different things I want to talk about.
The first thing I want to talk about is the naming of these argument labels and the internal parameter names.
So here in Objective-C you always have a selector piece, goes before the colon.
And then you have the name of the - at the internal parameter that you use when you're defining the method in your .m file.
In Objective-C you always have to write both of these, of course, and many times they're the same.
So you have some redundancy.
We do a little bit of syntax optimization here in Swift, so you just write the name once.
It serves both as the label and the internal name.
If you want those names to be different, fine, we can handle that, too.
You just write the two names next to each other.
The first one is the label because that's what's important for the caller to use.
And then the second one is the internal name that you're going to use within the implementation of your method.
The next thing I want to point out here is the Block.
So here we have a method that takes a Block, and Blocks in Objective-C get mapped into Closures in Swift.
You see, again, this is an implicitly unwrapped optional so that you can pass a nil Block in here.
Now the really great thing about getting Objective-C Blocks mapped into Swift Closures is that we get all of the great closure syntax that is provided by Swift, including trailing closures when your block is the last parameter.
So all of your block-based APIs that you've written, all the ones from Cocoa, when they're following the convention of putting the block last get this nice trailing closure syntax in Swift.
Let's talk a little bit about Initializers.
So in Objective-C we have init methods and init methods have a lot of conventions built around them.
They start with the word "init."
They should be returning instance type, although that's a fairly new invention.
So sometimes they're still returning ID.
And when you're implementing these things, you have a lot of requirements.
You need to call "super init."
You need to reassign "self."
You need to check "self," you need to return "self."
So all of this screams, we need something formalized in the language.
And so Swift has this notion of Initializers.
And we import Objective-C init methods as Swift Initializers.
How do we get from the top Objective-C code to the Swift code in the bottom?
Well, we find the init, so we match the init name and the camel-case string here.
We actually look forward a little bit to see if it's really initWith because that's extremely common.
And then we take the rest of that Selector, and lowercase the first character in it, and turn that into an argument label for the Swift Initializer.
Now, why do we do this?
Well, let's look at how we build objects in Objective-C versus in Swift.
So in Objective-C you do an alloc on your class and then you immediately send it an init message to initialize the Object.
These two steps are almost never separated.
Now in Swift we have our Initializers and we use this Unified Object Construction syntax where we write the name of the Class and then we pass arguments directly to the Initializer.
And notice here, we're using the argument label of fileURL to say which Initializer we're actually using and then give it the argument.
And, of course, we folded the alloc and the init together in this one nice syntax that also happens to work for all other types of in Swift whether they be structs or enums.
Okay. So let's talk about factory methods because this is the other way that we build Objects in Objective-C.
So here we have something from UIColor.
I've stepped away from UIDocument.
And they have colorWithRed blue green alpha.
And, of course, we can go and construct that by calling UIColor colorWithRed green blue alpha.
All of this can be directly imported in Swift.
It would just be a class method, colorwithRed, and green blue alpha as argument labels, and we could just call it on the class.
This would be fine.
However, we don't really love that they're two completely different kinds of initialization.
So we recognize the common patterns in how factory methods are described in Objective-C, and bring them in as Swift Initializers.
And the really great thing here is we get that common Initialization syntax for all of these Objective-C APIs.
You don't have to think, "Is there an init method for this?
Or is there a class method for this?"
It's there as an Initializer.
Do you like that?
[ Applause ]
Let's go a little bit down the stack and let's talk about Enums.
So here's the UIDocumentSaveOperation enum as defined in Objective-C.
And if we look at this we see a whole lot of redundancy.
This UIDocumentSave prefix is used for the enum and for both of its enum values.
Why is this?
Well, this is C.
The enum values in C are in a global namespace.
We can't call these enum values just ForCreating and ForOverwriting because that's going to stomp on some other completely different enumeration somewhere else in the system and cause havoc.
So we do this common prefix by convention.
It helps code completion find the right thing.
But when we're talking about Swift, it's also a great cue for us that we can do better.
And so we can import this NS-ENUM as a Swift enum chopping off all of those common prefixes to get us nice short names for the cases.
Now the reason we can do this is because the enum cases in Swift are scoped within the enum type itself.
How does this play out in actual code?
Well, okay, if we call fileNameExtensionForType saveOperation, we can refer to, say ForCreating, with its fully dotted name - class name.enum, the same dotted syntax we use for a number of anything in Swift.
But Swift has type inference.
We know that this method takes the UIDocumentSaveOperation, so there's absolutely no reason to write that.
You can just pass .ForCreating and we will infer the enum type from that.
I'd also like to talk about NSError.
So this is our pattern in Cocoa for dealing with errors.
And so there are many methods throughout Cocoa and throughout your own apps that take an NSError , and that's a C pointer to an NSError object.
We bring this in with a special type in Swift.
In fact, if you type alias for a much longer type name call NSErrorPointer.
We're going to see NSErrorPointer twice in this talk.
For now we're going to talk about how to use it when we're calling into the API.
And it's not actually all that much different from Objective-C.
So, if we bring this up, we declare a local variable.
It's called error.
It's a type NSError optional.
And we pass its address in when we're calling contentsForType error.
And so in this code we check whether we're getting back some contents from this.
Then we can deal with those contents.
If we fail to find any contents well, we probably have an error.
So we can go unwrap that optional error and present it to the user.
And if we fall through the else here, now we're in trouble because something failed and we have nothing we can do about it.
We hope that doesn't happen.
But this is the pattern you'll be using when dealing with NSError in Swift.
If you truly don't care about the error, you can also pass nil.
So we've walked through a lot of little pieces of the Objective-C mapping into Swift.
And there are a lot of rules that we've talked about that you're certainly not going to remember.
That's perfectly fine.
Xcode has your back here.
Use the tools to help you.
So if you're in Xcode, you're in some Swift Code, you can Command+Click on a class name.
And we'll show you the Swift projection of the underlying Objective-C class.
So take your favorite Cocoa class and look at how it maps into Swift.
Get a feel for the language, an intuitive feel for how these languages work together and you'll get into Swift really fast.
And the great thing is, all of these tools, all the rules I've talked about, apply equally to any Objective-C API when it comes into Swift.
It doesn't matter if it's Cocoa.
It doesn't matter if it's your own API.
The same rules apply, and you can view your own Objective-C APIs in Swift to get to know them better.
Now this works best when you're following "modern" Objective-C practices.
So these are using features like Properties, instancetype, marking your enumerations with NS-ENUM or NS-OPTIONS to describe more semantic information about what these enums actually mean in C.
We've also introduced NS-DESIGNATED-INITIALIZER this year to mark your designated Initializers and formalize a Designated Initializer pattern, both in Objective-C through additional warnings, and as the initialization model for Swift.
So, of course, we want you to follow all of these "modern" Objective-C practices but we don't want you to have to go it alone.
And so this year we introduced the Objective-C Modernizer that helps find these cases in your code where we could possibly modernize them to work with all these "modern" Objective-C features and give you a better projection into Swift.
And that Modernizer is discussed in the "What's New in LLVM" talk earlier today.
Highly recommend you catch it on video if you missed it.
With that, let's talk about id.
What is id in Objective-C?
It's kind of a placeholder in some sense.
It means, I have a value.
I know it's an object but I don't know or I don't care what the static type of that object is.
It's going to vary at runtime most likely.
And there's a couple of core operations that you can perform on id.
You can do upcasting on it.
So, if I have this variable object of type id, I can put an NSURL into it.
Later I can go reassign it and I can put a UIView on it.
That's perfectly fine.
They can both be upcasted essentially to id.
They're both objects.
I can do Message sends to id just directly by doing a Message Send.
I can subscript an id if I really feel like.
In Swift, any object is the equivalent to id.
And it provides these same core operations - Upcasting, Message Sends, Subscripting - that you can do on id in Objective-C.
Now one of the things we know from using id in Objective-C is that you sometimes have to be a little bit careful because if you send a message to an object that doesn't have a corresponding method, you're going to get a runtime failure that this is an unrecognized selector.
Now in Objective-C we have an answer for this.
Using this respondsToSelector idiom.
Do an if. Check whether it respondsToSelector, then do it.
In Swift we like to do a little bit better.
So let's take the same call and let's do a removeFromSuperview() call on this object.
And the thing to note here is that removeFromSuperview() on an object of unknown type, it may be there, it may not be there.
Well, how do we deal with this notion in Swift?
We use an "optional" that says there may be a value there; there may not be.
And so the reference to removeFromSuperview() on object is in effect, optional.
That means we can use the optional Chaining Operator here to - [ Applause ]
What we're doing, of course, is we're folding the respondsToSelector check in, so we do the reference, go look for RemoveFromSuperview.
If it's there, go on, call it.
If it's not there, stop evaluating this expression.
Now, something that id does that AnyObject does not do is implicitly downcast.
So I have Object, which is a type AnyObject, and I'm trying to assign it into a UIView.
This is going to produce a compiler error because this is a unsafe downcast.
How do we deal with this?
Well, there's really two cases here that need that you need to think about.
One case is, I know it's a UIView but for some reason that strong type information got lost when going through some API somewhere.
If I know for sure it's a UIView, I can use the cast operator, "as", to say, "Treat this object as a UIView."
We're going to do these kind of class check at runtime to make sure that's absolutely true.
But the type system will believe you at this point.
Now if you don't know whether this object is a UIView or not, you can use the "as?"
to perform a conditional downcast.
[ Applause ]
Think you guys have figured it out?
But just to be sure, this is doing "is kind of" class check.
And it's wrapping the result in an optional UIView.
It's nil if the check failed.
It has the UIView if the check succeeded.
We can do an if-let here to completely do this entire thing safely, and view in here is the UIView we were looking for.
So let's take a little bit of detour and talk about tiny bit of protocols.
Here's an Objective-C Protocol for a UITableViewDataSource and its Swift equivalent.
Not a whole lot new here.
But there are two things that I do I want to point out.
The first thing I want to point out is optional and required.
So in Objective-C optional and required are essentially modes in the protocol.
You say @optional, and everything that follows is optional up until the point where you hit an @required and then everything is required.
And we're not totally thrilled with this decision now.
And the basic reason is that you can't just look at one single declaration in the protocol and know whether it's optional or required.
You have to go scan up your protocol to find it.
And so we did something a little bit different in Swift in that requirements in protocol are required by default in Swift.
If you want to make them optional, then tag them with the optional attribute to make them optional.
The other thing I want to point out here.
We're doing a little bit of Protocol Inheritance and we're inheriting from NSObjectProtocol.
So in Objective-C we will have NSObject the class and NSObject the protocol.
And they have the same name so we have to add the "the class" or "the protocol" at the end when we talk about it.
The language keeps these in syntactically distinct points so the language isn't confused.
But in Swift we wanted to bring all these things into the same namespace because that's far more convenient for the general case.
And so we needed to rename something.
And essentially when there's a conflict between a class name and a protocol name, we'll append protocol to the name of the protocol.
Why did we do this?
Well, let's take a look at another use of id that we see in Objective-C, and that's protocol-qualified id.
So this dataSource here is an object of some unknown type.
But we know that the type conforms to the UITableViewDataSource protocol.
We describe that a little bit more directly in the Swift language by just saying the dataSource is a UITableViewDataSource!.
Now some of you here noticed with protocol-qualified id, you can have many different protocols if you want.
We can use the protocol keyword with angle brackets to describe more than one protocol.
Now, one of the things we do with Protocol Conformance is we have an object of unknown type and we want to determine, does it conform to the protocol?
This is the "conforms to protocol check" in the Objective-C runtime.
In Swift, we do this same thing with the conditional downcast operator.
So we can just ask, is my object the UITableViewDataSource" conforms to protocol check, happens in the runtime, captures the results in an optional.
Here we can go easily do that, call one of the methods and compute the number of rows in the first section of this TableViewDataSource.
Let's make our example a little bit more interesting.
Let's compute the number of rows in the last section.
So here we need to compute the number of sections that exist in the TableView, subtract one off of it, and then we can ask for the number of rows in that section.
Now there's a problem with this code.
And the problem is the number of sections in TableView, as you might remember, is an optional method.
It might not be there at runtime.
So we're going to need to compile error out of this because we need to deal with the optionality of this protocol method.
And we deal with this the same way we deal with optionality everywhere else in the Swift language, using the mechanisms we have.
So here we're going to use the chaining "?"
operator. We're checking, does my DataSource have a number of sections in TableView method?
If so, call it, given the TableView, and then we capture the result in numSections so we can compute the last section number and get the number of rows in the last section of our TableView.
That's about all we're going to talk about with Protocols here.
If you're interested in Protocols and some of the amazing things they can do, there's an "Advanced Swift" talk tomorrow morning.
It goes into more depth on those and their interaction with the generic system.
So, wrapping up here, AnyObject is Swift's equivalent to id.
The functionality is similar.
The ideas are similar and the uses are similar.
However, it's more safe by default.
Now we didn't talk about it, but there's also AnyClass, which is Swift's equivalent to class and has most of the same behaviors.
Now the other thing that we've seen is how Optionals are used throughout the language to represent dynamic checks.
We've taken "is kind of" class checks, conforms to protocol checks, responds to selector checks, and folded them all into the notion of Optionals within the language with their optimized syntax to make them easy to use and easy to do the right thing.
With that, let's switch gears a little bit and talk about Bridging of Cocoa data types.
Now first, let's talk a little bit about the native Strings, Arrays, and the Dictionaries within Swift.
The goal of Swift is to have one set of general-purpose native value types that you use for nearly everything.
These need to be safe by default.
This means bounds restricting for arrays, automatic memory management, and so on.
They need to have predictable performance so that you can look at code and have a sense of how it's going to behave with no surprises, how it's going to perform.
And, of course, we want arrays and dictionaries to be collections and they need to be strongly typed collections that work with any type.
We can't limit them just to objects because sometimes you need an array of strings or ints.
And we don't have a seed to fall back to for the cases where the other tools don't work.
This is it.
Now, to support having this one notion of one set of general purpose native value types, we're going to bridge from Cocoa's NSString, NSArray, NSDictionary, into the Swift-native equivalents.
So let's first talk a little bit about the native string type itself.
So, String is an efficient, Unicode-compliant string type.
Core string type of Swift has Unicode built in through and through so it makes it easy to work with.
We provide flexible and efficient high-level APIs to work with strings.
You can easily do concatenation, searches, prefix matches, sub-strings.
And the strings provide value semantics, which makes them easier to work with.
And value semantics is generally a fairly simple notion of, you know, if I have two variables of string type, modifying one of them doesn't affect the other one, all right.
This is very nice for a fundamental data type.
Now, of course, you can also think of strings as a unit, but you can also think of them as being composed of characters which, in fact, they are.
And so we can go walk over a string and using the for loop, and get all of the characters out of the string.
And you get the answer that you would expect.
There are five characters here even though there's no emoji at the end.
So I want to talk a little bit about characters and code points because the character that you're getting out of here is a full Unicode character.
It's not a UTF-8 code point or UTF-16 code point that you have to deal with.
It is a Unicode character.
And now, one of the challenges with the Unicode characters is, you really can't encode them efficiently in a way that treats a string as just an array of characters.
It would be too large.
And so what you generally see is that a string is encoded as, say, UTF-8 or UTF-16.
But working with those UTF-8 or UTF-16 code points, that requires Unicode expertise to get right all the time.
And so we made a really interesting decision here.
We decided not to provide the super low-level operations like length and characterAtIndex to let you poke directly at the UTF-16 or UTF-8 code points, or whatever is stored in the string because doing so causes big problems.
Instead we want you to use the high-level APIs and let the library do the hard work of dealing with all the intricacies of Unicode.
Of course, there's still common operations you want to use.
You may want to count the number of characters in a string, so there's this countElements algorithm.
It works on any sequence and allows you to, well, just count the number of characters in a string, and this produces the right answer, which is there are five characters in this string.
Some of you will want to work with code points, right.
You may be Unicode experts and that's wonderful.
You can get access to the code points.
There's a property UTF-16 that gives you a lazily computed view on the string producing the UTF-16 code points in that string.
And we can go walk over the 16-bit unsigned integer code points.
We can print out the number of code points here and, of course, you'll get the answer "6" because there are six UTF-16 code points in this string.
The last thing I want to talk about with strings is the relationship between string and NSSring.
So NSString has a wealth of really great text processing APIs that you've probably been using for years.
So we've made all those Foundation APIs directly available on the string type, so the APIs you know and love are there, and you can use them.
Now in doing so, we've made them a little bit more Swift.
We've tightened up the type signatures so that if you're going to split a string into its components, well, you're getting it back an array of strings rather than just an array of somethings.
Now you may have developed your own categories on NSString with additional functionality that you use within your own applications.
You can get to those with a simple Cast.
So you can take a Swift string, turn it into an NSString, so this is just a conversion, and then call your NSStringMethod.
If you find yourselves doing this a lot, feel free to just go ahead and extend the underlying string type.
Add your StringMethod, make it a little more Swift with strong type signatures, closures if you'd like.
But this should help you feel at home in Swift fairly quickly and use the String type.
Now let's move from String to a container.
Let's talk about Arrays.
So here we have toolbar items that is in an NSArray.
That's going to come into Swift as an array of AnyObject.
Now these two types are fairly similar.
You can iterate over them and what you're going to get out of it are values of type AnyObject.
They're objects but you don't know what kind of object it is.
You can subscript into them and, of course, you will get an AnyObject.
Now, in Swift, you tend to deal in typed arrays more often.
And so there are some other operations that the core language needs to provide for you to make this clean.
So maybe I'm composing my toolbar items into a Swift array and that Swift array is going to contain UIBarButtonItems.
That's what actually goes into the toolbar items property.
I can work with that Swift Array and then I can assign it into the AnyObject array.
So this is essentially doing a safe upcast of any array of ToolbarItems to any array of AnyObjects.
It also happens to be calling into Objective-C, which we'll get to in a minute.
Now we also see the flip side of this where we want to, say, iterate over all the ToolbarItems in this particular view controller and here we're going to get AnyObject values and, we talked about cast earlier, so we can downcast each of them.
This is fine but it's a little bit on the tedious side.
And so we have specialized syntax here to downcast an entire array at a time doing the "is kind of" class checks necessary to make this safe lazily behind the scenes.
And then you can walk over all with them.
[ Applause ]
Now, we've seen NSArrays in the Objective-C side, Swift arrays on the Swift side.
Let's take a little bit of a peek under the hood at how this actually works because you're going to be writing a lot of Swift code that interacts with a lot of Objective-C code and we want this to perform well.
So there's a Swift array.
And the Swift array actually has two internal representations.
Its first representation is probably what you'd expect out of Swift.
It's a native representation.
It has a length, which is the number of elements in the array.
It has a capacity that's used so we can algorithmically efficiently add things to the array.
And then it has the buffer of elements that are in the array.
And, of course, those buffered elements, whatever kind of array it is, that's how much storage they take.
If we have an array of 32-bit integers, each element takes 32 bits of storage.
There's not extra boxing going on here, no extra performance loss.
It's just a native buffer.
Now we also have this second representation and we do a couple of pointer tricks so that we can fit it into just a tiny amount of memory.
And that's the Cocoa representation.
So any Swift array can actually be an NSArray underneath as representation.
And all the operations on an array handle both of these representations.
So if I subscript my array and it happens to be an NSArray, we'll use object and index behind the scenes.
So you get the result that you want.
If we do append to such an array, well, we can flip the representation quickly and give you that efficient append operation.
So given these two representations, we can talk about the notion of bridging, of converting between an NSArray, as Objective-C would see, and a Swift array that you use within Swift.
There's two directions here: going to Objective-C and coming back.
So first, let's talk about coming back.
So we have an Objective-C method.
In this case, it's the getter for toolbar items.
In Objective-C, that returns NSArray.
In Swift, that's going to come back as an array of AnyObject.
How do we do this?
Well, given our two representations, it's extremely efficient to do it because we have our representation that can just take that NSArray directly.
All we need to do is one copy operation to make sure the contents don't change underneath us if it's a mutable array.
But the common case here is that it's not a mutable array.
It's an immutable NSArray and so this copy operation is trivial.
It's a message send, it's a retain, and that's it.
So its conversion is extremely fast.
Let's talk about the other direction, going from a Swift array to an NSArray.
So this would happen when we take, say, our ToolbarItems.
It's a Swift array.
And we call the Objective-C setter, which expects an NSArray.
Well, now we have an interesting question because there's two possible representations here.
There's the really easy answer.
It's already in the Cocoa representation and we can just hand off the NSArray, no work at all.
But the native one, that a different question entirely.
We could copy the whole buffer but that would be awful.
We could possibly go allocate a little shim object.
That's also possible.
Instead, we decided to make our native representation into a little bit of an Objective-C object [laughter].
It's already an NSArray.
And we've optimized the allocation here so we can build these objects super fast and just pass off our native representation as if it were an NSArray and it works beautifully on the Objective-C side.
[ Applause ]
I think that's enough of Bridging.
Let's talk about subclassing.
Okay. So, Swift objects are all Objective-C objects.
Now what this means is that, if you define a class in Swift, it has basic Objective-C interoperability built in.
We use the same layout as an Objective-C class so there's an "isa" pointer in there.
The "isa" pointer points out to Objective-C metadata.
There's the same underlying infrastructure, the thing that makes "arch" work and the basic frameworks work with retain and release.
You can expect a class.
That sort of thing.
They're all available.
Now, if you really want to make use of your classes from within your Objective-C code, well, then you should inherit from an Objective-C class, whether it's NSObject or some other class.
And this is going to expose your class to the Objective-C world and make all the things you write in Swift available also to your Objective-C code.
So we're going to continue with our UIDocument example from earlier and we're going to create a little MyDocument class that inherits from UIDocument.
And we're going to talk about a couple of the things that subclasses do.
They override methods.
So here we're going to override the handleError, userInteractionPermitted method.
And you do this exactly the same way as you'd do it if you were overriding a Swift method.
It doesn't matter.
The syntax is the same.
The fact that the super class is written in Objective-C?
Completely irrelevant to the syntax of the language and how you work with it.
Now one thing to note in Swift is that the "override" keyword is mandatory.
Why do we do that?
There's a couple of reasons for doing that.
One of the reasons is because when you look at a method, you probably want to know if the intention here is to override your super class's behavior because that's a really important part of your API.
It's a really part of understanding what this method is supposed to do.
Now the other thing it does is it helps overriding accidents.
For example, I meant to override something from my super class, but I typed part of the selector wrong and the method name no longer overrides.
My code isn't running and I have no idea why.
Well, with mandatory override, we catch that.
If you didn't override something and you thought you did, compiler will complain.
There's also the real surprise which is when you override something from your super class that you didn't even know existed.
And this is the case where you just wrote a method and maybe in this release that method happens to exist or maybe it doesn't exist in this release, but some joker added it to the next release in the frameworks that you use and now you're overriding something that you didn't know existed at the time.
We can catch that by requiring override throughout the language.
We could also talk a little bit about overriding properties.
So, in Swift, you don't override the getter or the setter separately.
Instead you override the property itself and then you provide a getter or a setter as appropriate.
So here we're doing something very simple.
We're overriding the description property and providing a new getter for it.
Now what this means to the Objective-C runtime, to your Objective-C code, is that you've overridden the getter.
But the semantic model in Swift is different.
It's based on overriding the actual thing that was declared.
In this case, the property.
As I mentioned before, NSError is going to come back.
So we have contentsForType error we're going to override in our subclass.
And remember that the Objective-C method took NSError, a C pointer to an NSError which could be nil.
The way we work with these in Swift is that the NSErrorPointer class provides a couple of operations that you would expect out of a pointer.
You can test it for nil, as we do in the if check here, to see whether we were actually given a valid point error where it's being given nil by our caller.
Now, if it's not nil, we can point at the memory location associated with that pointer by referring to it as error.memory and we can read from that memory or write to that memory by just reading or signing to it.
Now, and this error pointer is going to take care of the nitty-gritty details of making this auto-releasing to fit in with the code conventions of Cocoa NSError handling.
So it's actually fairly easy to deal with the C pointer from within the Swift world.
Now let's take a look at the Swift class that we've been building here.
We have MyDocument.
It inherits from UIDocument.
It has a property in it.
It has some method overrides.
It's just a Swift class through and through.
But all of this is accessible directly in your Objective-C code.
So if you project this into Objective-C, it would look like this.
All the same elements are there.
We have properties.
We have methods.
Now there's some interesting things to point out.
Well, for one, we have this item's property that is in an NSArray.
Remember, we talked about bridging here.
The original Swift code had an array of strings.
We bridged that seamlessly over to an NSArray that contains NSString objects for your Objective-C code to use.
So you can use strong typing in the Swift world and it maps over to the natural thing within the Objective-C world.
The other thing I want to point out is this really ugly name up top you've noticed.
So this is a mangled name.
Usually you're going to see this as MyApp.MyDocument, unless you're poking at the internal somewhere.
And the purpose of this mangled name is to put everything in a namespace of some sort so you don't have to prefix all of your class names.
Instead, what Swift does is it puts the module name, which is your target, your framework, or your app - that name into the names of the classes it creates so you can use the simple names that you want to use throughout your application and not worry about a conflict with something else in the system somewhere.
[ Applause ]
When you're writing your Swift Classes, you do need to be a little bit cognizant of the limits of Objective-C.
Swift has a lot of cool features; you might want to use them -Tuples, Generics and so on.
And if you go crazy in your classes and you use these features, you might be a little surprised that this generic method that returns a tuple doesn't show up in your Objective-C code because Objective-C has no way to express that signature.
There's nothing we can do.
We don't have tuples in Objective-C.
So if this happens to you and you're surprised by it, there's an attribute you can add to your method.
It's the objc attribute.
And what this does is it asks the compiler to check and make sure that this method or property or initializer or whatever is expressible in Objective-C so it can be used from your Objective-C code.
And if it's not expressible in Objective-C for some reason, the compiler will give you a hard error to tell you this is not something you can use from Objective-C.
Now the objc attribute actually has a second purpose.
And that's controlling the names that you see in the Objective-C side of things.
So, here's a property enabled.
It has a getter.
It has a setter.
In Objective-C this is going to come through as a property named "enabled," a getter named "enabled," and a setter named "setEnabled:" That's not Cocoa convention.
You'd really rather the call, the getter, "isEnabled".
And so to do that we just use the objc attribute, provide it with the selector "isEnabled" so we can control the mapping ourselves between these two languages.
I don't expect you to do this often, but it's there if you need it.
You can also do this for the name of a class.
And what we have here in the parentheses, in the objc attribute, is the non-named space name of a class.
So why would you do this?
Well, perhaps you're porting part of your application from Objective-C to Swift for some reason.
And so you had ABCMyDocument.
Now you just want to call it MyDocument because you're sick of typing ABC.
However, you have some archives that you still want to have work, because this is going to be a drop-in compatible implementation.
In Swift, for your Objective-C class, you can use the objc attribute to give this class the runtime name of ABCMyDocument and keep all of your archives working.
One last thing I promised to talk about, and that's CF Interoperability.
So by CF we're referring to all of the C-like APIs that work with the C objects.
So, this is Core Foundation.
This is Core Graphics and other frameworks, maybe some of your own frameworks.
And let's take a little look at using CF, particularly Core Graphics in Objective-C.
I'm going to do something really simple here.
I'm going to draw a gradient in a rectangle using Core Graphics.
Here's my start.
I need to go build up the ColorSpace and build up the Gradient.
Now there's a couple of things of here that I find non-optimal.
So the one thing is bridge casts.
So we're in ARC.
It's partly great.
It's handling our NSArray for us.
We're using the nice array literal syntax.
But now we need to do bridge casts between CGColorRef and id so we can put things into the NSArray.
And we have this CFArray cast sort of doing toll-free bridging there between the NSArray and the CFArray.
And there's also this semi-amusing thing that we're using three different kinds of arrays in four lines of code.
And you can write this - you can try to write this better.
I couldn't, actually, find a way to make it cleaner than this.
And it's really unfortunate because the NSArray gives us some useful behavior.
ARC is managing its lifetime for us.
We need the C Array because we need to put CGFloats in it, and we can't do that within NSArray.
And finally, we need to do the toll-free bridging over to CFArrayRef because that's what we use with Core Graphics APIs.
Now, moving along, we can create some points with CGPointMake and, of course, even though you're under ARC where memory management is automatic, it's not automated for CF things.
So we have to remember to release the ColorSpace and release the Gradient.
We feel like we can do a little bit better in the world of Swift.
So let's start again, this time in Swift.
And first, let's build our colorSpace.
So here we're just calling CGColorSpaceCreateDeviceRGB().
Nothing different about that.
However, the type that we infer for this ColorSpace variable is CGColorSpace.
Note the lack of a ref at the end of this.
This isn't some opaque pointer.
This is the CGColorSpace class that we've created.
What's the nice thing about being a class?
Well, that means we're in the ARC model and we're going to automatically manage the memory for you.
[ Applause ]
Let's go a little further and create that Gradient we talked about.
So here, remember, we need to pass a couple of arrays through.
We can use this nice Swift array literal syntax to form an array containing startColor and Color.
We're doing all of the bridging automatically here for you.
So we've created the NSArray we need.
We've toll-free bridged it to the CFArray behind the scenes so you don't have to deal with the fact that there are so many array types running around.
Did the exact same thing for the C parts.
So here we just have an array of floating point values.
So it's treated as a native Swift array of CGFloats that we bridged seamlessly to the underlying C array that this C function expects.
Let's keep going with our example here.
CGPoint. You can use CGPointMake if you want.
It's perfectly fine.
It works exactly the same way as it does in Objective-C.
However, whenever we import a struct, like CGPoint is a struct, we provide it with initializers that have labeled arguments.
And so a better way to build CGPoints in Swift is to just construct a CGPoint value using that same construction syntax we've been talking about throughout this talk.
And then use the argument labels x and y to make it absolutely clear what you're doing.
And this brings a little bit of a flavor of that nice Cocoa readability using argument labels into the underlying CF APIs.
And that's it for our example in Swift.
There's far fewer concepts that you have to deal with because we've automatically taken over the management.
[ Applause ]
Now you may have some of your own APIs that we refer to as explicitly bridged.
So these are CF-like APIs where we're not quite sure whether you're following all the CF memory conventions because, unlike the world of Cocoa which is fairly tame, and we've been following conventions fairly well for many years, we haven't been following them so well in C as a community.
And so we may have this function GetRandomColor, produces some random color.
When we pull this in, the Swift compiler doesn't know whether we can really trust that this returns plus zero or not.
It has get in the name but we're not sure.
And so we do the safe thing and we import it as an Unmanaged<CGColor which means we can't directly manage the memory here because we don't know what the conventions are.
So what is this Unmanaged thing?
So Unmanaged is actually a generic struct over an arbitrary T.
Now the details of generic structs we don't need to go into now.
They're covered in the Advanced talk which I highly recommend.
What we want to look at right now is just the simple API of this Unmanaged type.
We have two core operations - takeUnretainedValue, which you use for +0 returns, and takeRetainedValue which you use for +1 returns.
Now, when we call our CGColorGetRandomColor, we want to immediately use one of these two functions.
So we know that GetRandomColor returns a plus zero, so we're going to do a takeUnretainedValue of it.
Now the reason to do this immediately after the call is this gets us a CGColor which takes us right back into automatically managing memory for you.
So the window in which you have to do something with manual memory management is tiny.
It's just this one little line of code where you establish what the convention is for CGColorGetRandomColor.
Now, if you own CGColorGetRandomColor, you can audit your APIs to make sure they follow the Core Foundation naming conventions for memory management.
And when they do, you can use these annotations here in core foundation - CF-IMPLICIT-BRIDGING-ENABLED and DISABLED.
Put this over a whole header once you've audited all the methods in that header.
And when you do that, well, now your function when you use from Swift, gets you right back into the managed world directly.
So you have the great automatic memory management that Swift can provide for CF.
So let's wrap up here.
We've talked about a lot of different topics.
We've talked about interoperability between Swift and Objective-C.
We've talked about a whole lot of rules about how that works.
But let the tools and documentation help you.
They can show you Swift and Objective-C side-by-side so you can get a feel for how your Objective-C APIs work in Swift.
We've talked about some of the details of bridging Core Cocoa data types and using Swift's native types.
And we talked about automated CF memory management available in Swift.
For more information, check out the "Swift Programming Language Book," and also the "Using Swift with Cocoa and Objective-C" guide that goes into more details on the interplay between these two programming languages.
[ Applause ]