2014s407 Swift Interoperability In Depth
[ Silence ][ Applause ]>> Welcome.
So I'm Doug Gregor.
I'm an engineer on the Swift Compiler Team, and we're hereto 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 Cocoaand Cocoa Touch development.
Now, Cocoa's not written in Swift.
It's written in Objective-C, a language you've been usingfor years and that all of your apps are written in.
So, interoperability between these two very differentprogramming languages is absolutely critical.
So we're going to talk about how that interoperating worksat 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 feelin Swift and how to work with them, as well as workingwith some more Swift concepts like dealing with AnyObjectand doing dynamic checks on your types.
Then we're going to talk about bridgingof 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-Cand how they're mapped back into Objective-Cso that you can use these two languages together.
And, finally, we're going to talk about Core Foundationand Core Graphics, and this general notionof CF Interoperability within the Swift programming language.
Let's get started talking about working with Cocoa.
So Swift provides seamless access to Objective-C APIsthrough the Objective-C Module System we introduced last year.
So you can pull your Objective-C APIs whether they be from Cocoaor your own into Swift and use them.
And then Swift maps those Objective-C APIsinto 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 differencesbetween these two language, of course.
Swift also has some modern features that we usewhen expressing those Objective-C APIs in Swiftthat will make it look a little bit different,as well as the bridging of core Cocoa typesthat I mentioned earlier.
Now, despite all of these differences that you seewhen 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 languagefor the same great platform, the same great frameworks.
So we're going to walk through part of something we knowand 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 exceptfor 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 valueof 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 knowthat 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 optionalwith the exclamation point here.
And this gives us a nice balance.
It means that we can express the notion of niland you can test it against nil to do those checks.
However, you can also just directly access propertiesor directly call a method on it, or you can convert itdown to NSNil, and we'll unwrapthat optional object automaticallyfor you doing the checking.
So it's a fairly syntactically lightweight way of dealingwith nil in a language where nil is a much more explicit entitylike 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 optionalhere so that nil can be passedthrough since NSString doesn't have a notion of nil inside it.
And there's a number of Objective-C typesthat get mapped slightly differently into Swift.
So there's some very, very fundamental types like BOOLand 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 talkabout 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 allof the selector pieces from the Objective-C method are herein the method's signature in Swift.
The first selector piece has become the so-called base nameof the method.
The second selector piece, SaveOperation,has become a label on the second argument.
A really important thing here is that these labelsand their order are enforced at the call site.
So, you must call it as fileNameExtensionForType,saveOperation, just like you do in Cocoawith the exact same ordering, so to preservethat nice readability from Cocoa that we all know and love.
Now the other thing to note here is the consistency hereon the Swift side.
All of the names and the colons and the parenthesesand the commas are in exactly the same placesin the declaration of the method in the middleand in the call site of the method at the bottom.
So the kind of consistency we like outof building a new language.
Let's look at a little bit more complicated method herewhere 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 namingof 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 parameterthat you use when you're defining the methodin 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 importantfor the caller to use.
And then the second one is the internal name that you're goingto 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 optionalso that you can pass a nil Block in here.
Now the really great thingabout getting Objective-C Blocks mapped into Swift Closures isthat we get all of the great closure syntax that is providedby Swift, including trailing closureswhen 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 conventionof putting the block last get this nice trailing closuresyntax in Swift.
Let's talk a little bit about Initializers.
So in Objective-C we have init methodsand 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 formalizedin 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 codeto the Swift code in the bottom?Well, we find the init, so we match the init nameand the camel-case string here.
We actually look forward a little bit to seeif 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 objectsin Objective-C versus in Swift.
So in Objective-C you do an alloc on your classand then you immediately send it an init messageto initialize the Object.
These two steps are almost never separated.
Now in Swift we have our Initializersand we use this Unified Object Construction syntaxwhere we write the name of the Classand then we pass arguments directly to the Initializer.
And notice here, we're using the argument label of fileURL to saywhich Initializer we're actually usingand then give it the argument.
And, of course, we folded the alloc and the init togetherin this one nice syntax that also happens to workfor all other types of in Swift whether they be structsor enums.
Okay.
So let's talk about factory methodsbecause this is the other waythat 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 constructthat 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 lovethat they're two completely different kindsof initialization.
So we recognize the common patternsin how factory methods are described in Objective-C,and bring them in as Swift Initializers.
And the really great thing here is we getthat common Initialization syntax for allof 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 stackand let's talk about Enums.
So here's the UIDocumentSaveOperation enumas defined in Objective-C.
And if we look at this we see a whole lot of redundancy.
This UIDocumentSave prefix is used for the enumand 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 ForCreatingand ForOverwriting because that's going to stompon some other completely different enumeration somewhereelse 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 cuefor us that we can do better.
And so we can import this NS-ENUMas a Swift enum chopping off all of those common prefixesto get us nice short names for the cases.
Now the reason we can do this is because the enum casesin Swift are scoped within the enum type itself.
How does this play out in actual code?Well, okay, if we call fileNameExtensionForTypesaveOperation, we can refer to, say ForCreating,with its fully dotted name - class name.
enum,the same dotted syntax we usefor 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 .
ForCreatingand 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 Cocoaand 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 aliasfor a much longer type name call NSErrorPointer.
We're goingto see NSErrorPointer twice in this talk.
For now we're going to talk about how to use itwhen 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 callingcontentsForType error.
And so in this code we check whether we're getting back somecontents 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 errorand present it to the user.
And if we fall through the else here, now we're in troublebecause 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 dealingwith 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 piecesof the Objective-C mapping into Swift.
And there are a lot of rules that we've talkedabout 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 projectionof the underlying Objective-C class.
So take your favorite Cocoa class and lookat how it maps into Swift.
Get a feel for the language, an intuitive feelfor how these languages work together and you'll getinto Swift really fast.
And the great thing is, all of these tools,all the rules I've talked about, apply equallyto 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-CAPIs 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-OPTIONSto describe more semantic informationabout what these enums actually mean in C.
We've also introduced NS-DESIGNATED-INITIALIZER thisyear to mark your designated Initializersand 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 youto have to go it alone.
And so this year we introduced the Objective-C Modernizerthat helps find these cases in your codewhere we could possibly modernize them to workwith all these "modern" Objective-C featuresand give you a better projection into Swift.
And that Modernizer is discussed in the "What's Newin 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 knowor 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 operationsthat 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 directlyby 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 isthat you sometimes have to be a little bit carefulbecause if you send a message to an objectthat doesn't have a corresponding method,you're going to get a runtime failurethat 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 calland let's do a removeFromSuperview() callon 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 hereto -[ 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.
We're done.
Now, something that id doesthat AnyObject does not do is implicitly downcast.
So I have Object, which is a type AnyObject, and I'm tryingto assign it into a UIView.
This is going to produce a compiler errorbecause this is a unsafe downcast.
How do we deal with this?Well, there's really two cases here that needthat you need to think about.
One case is, I know it's a UIView but for some reasonthat strong type information got lost when goingthrough 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 runtimeto 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 UIViewor 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 hereto 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 talkabout tiny bit of protocols.
Here's an Objective-C Protocol for a UITableViewDataSourceand 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 optionaland required are essentially modes in the protocol.
You say @optional, and everythingthat follows is optional up until the pointwhere 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 lookat one single declaration in the protocoland 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 Swiftin that requirements in protocol are requiredby default in Swift.
If you want to make them optional, then tag themwith the optional attribute to make them optional.
The other thing I want to point out here.
We're doing a little bit of Protocol Inheritanceand we're inheriting from NSObjectProtocol.
So in Objective-C we will have NSObject the classand 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 pointsso the language isn't confused.
But in Swift we wanted to bring all these thingsinto the same namespace because that's far more convenientfor the general case.
And so we needed to rename something.
And essentially when there's a conflict between a class nameand a protocol name, we'll append protocolto the name of the protocol.
Why did we do this?Well, let's take a look at another use of id that we seein 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 conformsto the UITableViewDataSource protocol.
We describe that a little bit more directlyin the Swift language by just saying the dataSource isa UITableViewDataSource!.
That's it.
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 bracketsto describe more than one protocol.
Now, one of the things we dowith Protocol Conformance is we have an object of unknown typeand 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 thingwith 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 methodsand compute the number of rows in the first sectionof 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 existin the TableView, subtract one off of it, and then we can askfor 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 thisbecause we need to deal with the optionalityof this protocol method.
And we deal with this the same way we dealwith 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 numberof sections in TableView method?If so, call it, given the TableView,and then we capture the result in numSectionsso we can compute the last section numberand get the number of rowsin 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 someof the amazing things they can do,there's an "Advanced Swift" talk tomorrow morning.
It goes into more depth on those and their interactionwith 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 mostof the same behaviors.
Now the other thing that we've seen is how Optionals are usedthroughout 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 Optionalswithin the language with their optimized syntaxto make them easy to use and easy to do the right thing.
With that, let's switch gears a little bit and talkabout 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 setof general-purpose native value types that you usefor 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 lookat code and have a sense of how it's going to behavewith no surprises, how it's going to perform.
And, of course, we want arrays and dictionariesto be collections and they need to be strongly typed collectionsthat work with any type.
We can't limit them just to objectsbecause sometimes you need an array of strings or ints.
And we don't have a seed to fall back to for the caseswhere the other tools don't work.
This is it.
Now, to support having this one notion of one setof general purpose native value types, we're going to bridgefrom Cocoa's NSString, NSArray, NSDictionary,into the Swift-native equivalents.
So let's first talk a little bitabout the native string type itself.
So, String is an efficient, Unicode-compliant string type.
Core string type of Swift has Unicode built in throughand through so it makes it easy to work with.
We provide flexibleand 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 composedof 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 emojiat the end.
So I want to talk a little bit about characters and code pointsbecause the character that you're gettingout of here is a full Unicode character.
It's not a UTF-8 code point or UTF-16 code pointthat 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 waythat treats a string as just an array of characters.
It would be too large.
And so what you generally see isthat 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 operationslike length and characterAtIndex to let you poke directlyat the UTF-16 or UTF-8 code points, or whatever is storedin the string because doing so causes big problems.
Instead we want you to use the high-level APIsand let the library do the hard work of dealingwith 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 viewon the string producing the UTF-16 code pointsin that string.
And we can go walk over the 16-bit unsigned integercode 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-code points in this string.
The last thing I want to talkabout with strings is the relationshipbetween string and NSSring.
So NSString has a wealthof really great text processing APIsthat you've probably been using for years.
So we've made all those Foundation APIs directlyavailable on the string type, so the APIs you knowand 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 thatif you're going to split a string into its components,well, you're getting it back an array of strings ratherthan just an array of somethings.
Now you may have developed your own categories on NSStringwith additional functionality that you usewithin 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 aheadand extend the underlying string type.
Add your StringMethod, make it a little more Swiftwith strong type signatures, closures if you'd like.
But this should help you feel at home in Swift fairly quicklyand 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 getout 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 operationsthat the core language needs to providefor you to make this clean.
So maybe I'm composing my toolbar items into a Swift arrayand 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 itinto the AnyObject array.
So this is essentially doing a safe upcast of any arrayof 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 ToolbarItemsin this particular view controller and here we're goingto 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 hereto downcast an entire array at a time doing the"is kind of" class checks necessaryto 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 hoodat how this actually works because you're goingto be writing a lot of Swift code that interacts with a lotof 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 expectout 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 usedso we can algorithmically efficiently add thingsto the array.
And then it has the buffer of elements that are in the array.
And, of course, those buffered elements, whatever kindof 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 representationand we do a couple of pointer tricks so that we can fit itinto just a tiny amount of memory.
And that's the Cocoa representation.
So any Swift array can actually be an NSArray underneathas representation.
And all the operations on an array handle bothof 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 youthat efficient append operation.
So given these two representations,we can talk about the notion of bridging, of convertingbetween 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 itbecause we have our representationthat can just take that NSArray directly.
All we need to do is one copy operationto make sure the contents don't change underneath usif 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 questionbecause there's two possible representations here.
There's the really easy answer.
It's already in the Cocoa representationand 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 representationinto a little bit of an Objective-C object [laughter].
It's already an NSArray.
And we've optimized the allocation hereso we can build these objects super fastand just pass off our native representationas if it were an NSArray and it works beautifullyon 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 workwith 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 classesfrom 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 worldand make all the things you write in Swift available alsoto your Objective-C code.
So we're going to continue with our UIDocument examplefrom earlier and we're going to create a little MyDocument classthat inherits from UIDocument.
And we're going to talk about a coupleof 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 itif 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 languageand 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 isto override your super class's behaviorbecause that's a really important part of your API.
It's a really partof 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 wrongand 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 iswhen you override something from your super classthat you didn't even know existed.
And this is the case where you just wrote a method and maybein this release that method happens to existor maybe it doesn't exist in this release,but some joker added it to the next release in the frameworksthat you use and now you're overriding somethingthat you didn't know existed at the time.
We can catch that by requiring override throughoutthe language.
We could also talk a little bit about overriding properties.
So, in Swift, you don't override the getteror the setter separately.
Instead you override the property itselfand then you provide a getter or a setter as appropriate.
So here we're doing something very simple.
We're overriding the description propertyand 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 goingto 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 isthat the NSErrorPointer class provides a couple of operationsthat 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 errorwhere it's being given nil by our caller.
Now, if it's not nil, we can pointat the memory location associated with that pointerby referring to it as error.
memory and we can readfrom that memory or write to that memoryby just reading or signing to it.
Now, and this error pointer is going to take careof the nitty-gritty details of making this auto-releasingto fit in with the code conventionsof Cocoa NSError handling.
So it's actually fairly easy to deal with the C pointerfrom within the Swift world.
Now let's take a look at the Swift classthat 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 directlyin 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 propertythat 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 NSArraythat contains NSString objectsfor your Objective-C code to use.
So you can use strong typing in the Swift world and it mapsover to the natural thing within the Objective-C world.
The other thing I want to point out is this really ugly nameup 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 everythingin a namespace of some sort so you don't haveto 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 createsso you can use the simple names that you wantto use throughout your application and not worryabout 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 cognizantof the limits of Objective-C.
Swift has a lot of cool features; you might wantto use them -Tuples, Generics and so on.
And if you go crazy in your classesand you use these features, you might be a little surprisedthat this generic method that returns a tuple doesn't showup in your Objective-C code because Objective-C has no wayto 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 checkand make sure that this method or property or initializeror whatever is expressible in Objective-C so it can be usedfrom your Objective-C code.
And if it's not expressible in Objective-C for some reason,the compiler will give you a hard errorto tell you this is not something you can usefrom Objective-C.
Now the objc attribute actually has a second purpose.
And that's controlling the names that you seein 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 ourselvesbetween 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 applicationfrom Objective-C to Swift for some reason.
And so you had ABCMyDocument.
Now you just want to call it MyDocumentbecause you're sick of typing ABC.
However, you have some archives that you still wantto have work, because this is goingto be a drop-in compatible implementation.
In Swift, for your Objective-C class,you can use the objc attributeto give this class the runtime name of ABCMyDocumentand 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 APIsthat 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 ColorSpaceand 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 idso we can put things into the NSArray.
And we have this CFArray cast sortof doing toll-free bridging therebetween the NSArray and the CFArray.
And there's also this semi-amusing thingthat we're using three different kinds of arraysin 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 unfortunatebecause the NSArray gives us some useful behavior.
ARC is managing its lifetime for us.
That's great.
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 bridgingover to CFArrayRef because that's what we usewith Core Graphics APIs.
Now, moving along, we can create some pointswith CGPointMake and, of course, even though you're under ARCwhere memory management is automatic,it's not automated for CF things.
So we have to remember to release the ColorSpaceand release the Gradient.
We feel like we can do a little bit betterin 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 inferfor 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 goingto automatically manage the memory for you.
[ Applause ]Let's go a little further and createthat Gradient we talked about.
So here, remember, we need to pass a couple of arrays through.
We can use this nice Swift array literal syntaxto 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 scenesso you don't have to deal with the fact that there areso 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 CGFloatsthat we bridged seamlessly to the underlying C arraythat 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 initializersthat have labeled arguments.
And so a better way to build CGPoints in Swift isto just construct a CGPoint value usingthat same construction syntax we've been talkingabout throughout this talk.
And then use the argument labels x and yto make it absolutely clear what you're doing.
And this brings a little bit of a flavorof that nice Cocoa readability using argument labelsinto the underlying CF APIs.
And that's it for our example in Swift.
It's smaller.
It's easier.
There's far fewer concepts that you have to dealwith because we've automatically taken over the management.
[ Applause ]Now you may have some of your own APIs that we referto as explicitly bridged.
So these are CF-like APIswhere we're not quite sure whether you're following all theCF memory conventions because, unlike the world of Cocoawhich is fairly tame, and we've been following conventionsfairly well for many years, we haven't been following themso 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 wecan 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 itas an Unmanaged<CGColor>which means we can't directly manage the memory herebecause we don't know what the conventions are.
So what is this Unmanaged thing?So Unmanaged is actually a generic structover an arbitrary T.
Now the details of generic structs we don't needto 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 APIof this Unmanaged type.
We have two core operations - takeUnretainedValue,which you use for +returns, and takeRetainedValuewhich 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 immediatelyafter the call is this gets us a CGColorwhich takes us right backinto automatically managing memory for you.
So the window in which you have to do somethingwith manual memory management is tiny.
It's just this one little line of codewhere you establish what the convention isfor CGColorGetRandomColor.
Now, if you own CGColorGetRandomColor,you can audit your APIs to make sure they follow the CoreFoundation naming conventions for memory management.
And when they do, you can use these annotations herein core foundation -CF-IMPLICIT-BRIDGING-ENABLED and DISABLED.
Put this over a whole header once you've audited all themethods in that header.
And when you do that, well, now your function when you usefrom Swift, gets you right back into the managed world directly.
So you have the great automatic memory managementthat Swift can provide for CF.
So let's wrap up here.
We've talked about a lot of different topics.
We've talked about interoperabilitybetween 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-sideso you can get a feel for how your Objective-C APIs workin Swift.
We've talked about some of the detailsof bridging Core Cocoa data typesand using Swift's native types.
And we talked about automated CF memory management availablein Swift.
For more information, check out the"Swift Programming Language Book," and also the "Using Swiftwith Cocoa and Objective-C" guide that goesinto more details on the interplaybetween these two programming languages.
Thank you.
[ Applause ]