Discover new features that make it easier than ever to craft Objective-C APIs that work beautifully in Swift, as well as new Swift language features that provide even better interoperability. Apple engineers will also discuss enhancements to Apple's SDKs that improve the Swift experience.
JORDAN ROSE: Good afternoon, everyone.
My name is Jordan Rose.
JORDAN ROSE: Wow.
I haven't even done anything yet.
My name is Jordan Rose.
Joining me later will be my colleague, Doug Gregor.
We are here to talk to you about the language changes we made
in both Swift and Objective-C over the last year,
especially in the areas of interoperability.
And this is important because all Objective-C APIs are
available in Swift.
And in Xcode 7 we made it even easier
to see how this mapping works.
Go to any Objective-C header
and choose the 'show related items' button
in the top-left corner.
This will bring down a menu of related items,
one of which is 'generated interface.'
And this will show you the Swift mapping for that header.
This is the exact same view that you got
in Xcode 6 using the 'jump to definition' feature,
but now you can get it easily from any header in your target.
So we are going to be talking about a variety
of improvements today that we have made to Swift for working
with Objective-C, and that we have been making
to Objective-C itself.
We will start off with some of the basic features working
between Swift and Objective-C, and at the details
of the new error-handling feature and how that works
across the language boundaries.
After that, we are going to talk
about the three major improvements we've made
to Objective-C in the last year, nullability annotations,
lightweight generics, and kindof types.
Let's start on the Swift side of things.
We just saw how easy it is
to get the Objective-C APIs into Swift.
But a lot of people come up with the question,
when is my Swift exposed to Objective-C?
And so, let's go over the rules for this.
If you have a class that's a subclass of NSObject,
then by default, its methods
and properties are exposed to Objective-C.
In this case, we have a class MyController that's a subclass
That's indirectly a subclass of NSObject,
so this refresh method will be exposed to Objective-C.
However, if you mark that method as private,
that means it's only supposed to be visible to the current file.
So in this case, Swift will not expose the method
to Objective-C by default.
Additionally, if you are only using --
if you are using some kind of Swift-only feature,
like this unusual return type here, then, again,
there's no way to expose this method to Objective-C
and Swift won't even try.
Finally, if you are not a subclass of NSObject
but simply conforming to an Objective-C protocol,
then you have to take extra care to make sure
that your methods actually satisfy the requirements
of the protocol.
And in Xcode 7, you will get a warning for this.
In this case, 'web view did start load' is non-objc,
and so it cannot satisfy the requirements
of the 'UI web view delegate protocol.'
So that covers the defaults.
What happens when you want to change those
from that default behavior?
So let's go back to that version of MyController here
with the refresh method, and I want to expose it
to Objective-C, but it really depends --
what I want to do next really depends on what I need to do
with this refresh method.
So, if I'm going to make this, say, something that I want
to use an interface builder or maybe it's a property
that I want to use from Core data,
we have dedicated attributes for these,
and adding that attribute is all you need to do.
So, if you use the IBAction attribute as shown here,
that's all you need to do
to make this refresh method a valid action
in interface builder.
Similarly, if you are looking to use a property
with foundations key value observing system,
or Cocoa bindings, all you need
to do is add the dynamic modifier.
This tells Swift that the implementation
of this property might be replaced at run time
by the key value observing system.
But if you really just want to expose a particular method
or property to Objective-C,
you can always just use the plain-old at-objc modifier,
or objc attribute -- sorry -- and this will expose a method
or objective to Objective-C
without any additional semantics.
The objc attribute is also useful for one other thing,
which is to figure out why something is not visible
in Objective-C when you thought it would be.
So if I tried to apply this to that other version of Refresh
that has the unusual result type here,
then I will get an error message saying this 'method cannot be
marked at-objc because its result type cannot be
represented in Objective-C.'
All of these rules are covered in the 'Using Swift with Cocoa
and Objective-C' guide, which is available online
So now we've covered the defaults, and we've covered what
to do when you want to override those defaults
to make things more ObjC.
But what if you have the opposite problem?
Let's look at this class here: calculator controller.
It has two methods named 'perform operation.'
One of them takes one kind of closure
and the other takes a different kind of closure.
Swift is able to differentiate these methods purely based
on their argument types.
But Objective-C doesn't work like this.
In Objective-C, methods are only differentiated
by name, not by type.
And so in this case, Swift knows this might be an issue
and it will give you an error message.
Now, you have always been able
to fix this using the selector form of the ObjC attribute.
So if I write this code, then I've renamed the bottom method
to 'perform binary operation,
when I'm accessing it from Objective-C.
The top method is still named 'perform operation.'
In Xcode 7, we've added another option for solving this problem,
which is the non-ObjC attribute.
As you might have expected,
this will take something that's normally exposed to Objective-C
and prevent it from being exposed as such.
You can apply the non-ObjC attribute to any method,
property, subscript, or initializer.
So that's a fair amount about Objective-C and methods,
but how about something lower level.
Let's talk about C.
So there are a few people in this room that are really happy
that we have a slide called function pointers.
[Laughter] A function pointer is what C uses for callbacks.
That means they are kind of like closures,
but they can't carry any additional state with them.
What do I mean by that?
Let's say I'm in Swift and I'm trying
to call this C function, funopen.
It takes a lot of arguments.
You don't have to know what they all are.
One of them is a callback.
In this callback, I'm trying to use self to do something.
Now, self is not an argument to this closure.
So it has to be stored away somewhere
for the closure to access later.
That's what we mean by a closure carrying state.
So when you try to use this closure, with this API,
you get an error message.
Now, in Swift 1.2, C function pointers weren't very useful.
You had this C type that is shown on the top,
and it came into Swift as this opaque, C function pointer type.
You could pass it around but you couldn't do much else with it.
In Swift 2.0, we've just made these a special kind
of closure marked with the convention-C attribute.
You can create these in Swift,
pass them around, and even call them.
Which means there's a whole family of C APIs
that you can now access directly in Swift
that you couldn't before.
JORDAN ROSE: So those are just two
of the little things we have done to enhance the bridge
from Swift and to C and Objective-C.
But there's also some big-name features this year
that have had some really big impacts
on this language bridging.
The most important, of course, being error handling.
Now, if you haven't really heard
about the error handling model yet, essentially we took a lot
of lessons from Cocoa's NSError paradigm and the rules
and the conventions that surrounded that,
and used what we learned from that
to make a new language feature,
represented by the 'throws' keyword.
This was covered in a lot of depth in this morning's talk
"What's New In Swift."
Which was -- which you -- if you didn't make it to that,
I strongly suggest you check it out later on,
to find out really how all this error handling stuff works.
But what I want to focus on now is specifics about this going
between the two languages.
And one thing I want you to understand is
that this isn't just a mapping from Objective-C into Swift.
It's also how Swift APIs get exposed back to Objective-C.
So this mapping is bidirectional.
Let's take a closer look at the return types here.
In Objective-C, the error conventions say
that returning a nil value represents a failure case.
That's when this 'out error' parameter is going
to be populated.
In Swift, however, that's entirely covered
by the error handling model, and so the return type you will see
in Swift is a non-optional object type.
Similarly in Objective-C,
you can also have a Boolean return value
where the no case is the failure case.
Again, that's entirely covered by the Swift model
and so the return type you will get will be void.
Now, on both of these examples, I have shown that these methods
in Objective-C have multiple parameters,
only one of which is the error parameter,
but there are also cases where methods only have one parameter
and you will get something
like 'check resource is researchable and return error.'
As you can see in Swift, since we already know
that the method can return an error
from that 'throws' keyword,
we will chop off those last three words
for you, just for you!
[Laughter] Now, all of this is about what happens
when you have the NSError-star-star type,
when you are using the really basic form
of the NSError conventions.
What happens in other cases?
Well, we just keep things as is.
If you have an NSError in Objective-C, it will come
into Swift usually as an optional NSError reference
and you can handle it as appropriate
for whatever API you are using.
Remember that NSError conforms to Swift's error type protocol,
so you can also use it
with Swift's own error handling mechanisms.
All of this shows that Swift is well equipped to deal
with all the errors coming from Objective-C.
But what if I call a method from Objective-C,
and it's a Swift method that produces a Swift error?
Now, of course, we need this to work.
Let's find out how it works.
Here I have a type named 'request error.'
It's a new type I'm defining using Swift's error system.
It conforms to the error type protocol, and in this case,
it's an enum that only has one possible enum case.
I can use this error in a method very easily.
Here I'm defining a 'send request' method.
I mark it with the 'throws' keyword to indicate
that it can fail, and then I actually use the 'throw'
statement when I hit that failure condition.
Now, if I try to call this method from Objective-C,
it ought to just work.
Let's see what that looks like.
The first thing to notice is that the name
of the method has changed.
Instead of just 'send request,
we now have 'send request error.'
The name that you would have used
if you had written this method in Objective-C to begin with.
Additionally, we're just using a plain-old NSError type,
from foundation here, even though the error
that we produced came from Swift.
And what's more, that error type actually contains
If we print the domain and code that go with this error,
we will see that it turns out to be the type and the raw value
of the enum case that we saw before.
Now, there's one more nice thing that's going on here.
I marked this enum with the ObjC attribute.
This is a feature we added in Xcode 6.3.
If you mark an enum with the ObjC attribute,
then it will get printed into your generated header.
The header that exposes the Objective-C side
of your Swift classes.
In Xcode -- sorry -- in Xcode 7,
we've added one more little nice feature here.
This is an enum that conforms to the error type protocol,
so we'll also generate a string constant representing the
Now, all of this is great for errors you have defined
in Swift, and you probably want to run out and use this
for your own classes, but then the errors that come back
from Cocoa and the rest of the SDKs start
to feel a little lacking.
And, don't worry, we have got you covered there too.
So if you were at the presentation earlier today,
you might have seen this preflight method
which is checking that a resource is reachable
and then catching some various error cases.
Now one of the error cases here is listed
as 'NSURLError, file does not exist.'
That's an error that comes from Cocoa.
Why is that showing up, using the Swift notation?
Well, we have taken the most common error types throughout
our SDKs and made it so that you can use them
with Swift's own catch syntax.
So there's are all sorts of errors you can use here.
And the general idea that you should take away from this,
is that errors should feel like NSError when you're
in Objective-C, and they should feel like Swift errors
when you are in Swift.
Things should just work.
So that's just some of the enhancements we've made to Swift
in the area of interoperability over the last year.
So to talk about the enhancements we've made
in the Objective-C side of the world,
I would like to hand it over to Doug.
DOUG GREGOR: Thank you.
Thank you, Jordan.
So today I would like to talk
about three new Objective-C features we've added this year.
These features can be used
to make your Objective-C code better,
your Objective-C APIs better, make them reflect better
into Swift, and improve static type safety in your Objective-C.
The first thing we are going to talk
about is nullability for Objective-C.
So take a look at this bit of Objective-C code.
Lots of pointers here.
Which one of these can be nil?
The code doesn't tell you.
If you go read the documentation,
maybe it will tell you if you are feeling lucky today.
You could go write some tests
and see what you think it behaves like or maybe guess,
but that's not really good.
There's really missing information here.
When we introduced Swift last year,
this lack of information became much more apparent
in these implicitly unwrapped optionals,
which essentially means we don't know
if it can be nil on the Swift side.
So we weren't too thrilled with this,
and so after releasing Swift 1.0, we went
and audited a couple thousand pointers
within our own core frameworks to tell the compiler
which of these pointers can be nil.
And the interfaces after this audit got much, much cleaner.
Now, we are only using optional types
where nil is actually something you have to deal with,
and everything else is non-optional.
This is still not that wonderful,
because this knowledge is baked into the compiler.
It's not something you can do.
So with Xcode 6.3, we introduced nullability qualifiers
So a nullability qualifier is something you can add
to a C/Objective-C pointer
to state whether it accepts nil or not.
Of course, this better communicates what your API
Does it accept nil?
Does that make sense for it?
It helps our tools do better static checking
to catch bugs before they manifest at run time,
and it makes the Swift experience so much better
with your Objective-C APIs!
Now, there are three nullability qualifiers.
Nullable, which indicates that the pointer may be null.
This, of course, maps into a Swift optional.
And then there's non-null.
So this indicates that null or nil is not a meaningful value.
Now, for a non-null pointer, it could end up being nil
in an Objective-C program.
Maybe it comes because we messaged nil at some point
and the nil propagated through
and maybe this has worked in the past.
The compiler is not going to change the way it generates code
because of a non-null annotation.
But this indicates the intent of the API author
that nil does not make sense here.
We also have a third qualifier, and that is null-unspecified.
This is for cases where neither nullable nor non-null is
actually the right thing, and we map these into Swift
as the same implicitly unwrapped optional you would get
if we knew nothing about the pointer whatsoever.
And the most important thing
about nullability qualifiers is we've rolled them
out throughout our SDKs.
Alright, so instead of just covering a couple
of core frameworks,
we've covered the majority of the SDKs.
So this gives a much, much better Swift experience
with true optionals where they actually matter
and non-optionals everywhere else.
For your Objective-C code, it means you are going to start
to see new warnings for places
where you have been misusing APIs.
So, here, for example, you see a warning that you've passed null
or nil to a method that did not expect it here.
It is not part of the API contract.
Now maybe passing a nil has worked before;
it may continue to work.
But you should heed these warnings,
because the API author has told you,
you should not pass nil here, it's good to be careful
because it may change in the future.
Now, let's say you want
to add nullability qualifiers to your own headers.
The place to start is with an audited region.
So, these are described by 'NS-assume non-null begin,
'NS-assume non-null end;
bracket your header with these macros.
What this does is it allows the compiler
to make default assumptions about pointers
that are not otherwise annotated.
So, if you have a single level pointer, that's going
to be assumed non-null, because what we've found is
that nil is not a meaningful value for most of our APIs.
The other interesting special case here is
Where you're doing error handling in Objective-C,
these are assumed to be nullable at both levels,
because that's the way you work with them for nullability.
Now the defaults are good, they should cover most of the cases,
but that means you have to annotate the exceptional cases.
So here we are marking the super view property as being nullable,
because, of course, not every view has a super view.
Nil has meaning there.
Hit test with event has a nullable parameter.
You don't have to pass in an event to do hit testing and,
of course, the result is nullable
because nil has meaning there.
It means we didn't hit anything.
Now, this is where null-unspecified comes up.
Say you are auditing a header.
You run into some really weird implementation that's been
You have no idea what it does with nil.
It hasn't been documented.
Maybe it's doing something really, really interesting
with messaging nil that may or may not work and the only guy
that can answer it retired five years ago.
Great place to use null unspecified.
Just mark it as null unspecified.
This means, 'I thought about it, I couldn't come to an answer.'
The best thing to do is keep it implicitly unwrapped optional
in Swift, keep it null-unspecified here.
You can always come back to it later.
So when auditing, you really want
to get some good breadth early
to make your APIs much, much better, faster.
Now, when you go down to C,
things get a little bit more murky.
So we have all of the same qualifiers but they need
to be preceded by the double-underscore.
Now, these double-underscored keywords, those qualifiers,
can be used on any pointer, anywhere.
The important rule here is that the qualifier goes to the right
of the pointer it applies to, the same place that const
or volatile would go to, to apply to that pointer.
This is particularly important for multilevel pointers
like this values parameter here
where the outer pointer is nullable, because you can pass
in nil to this parameter so long as num-values is also zero.
The inner pointer is non-null, because when you are passing
in an array of values, all of those values must be non-null
to work with CF array.
That's all we're going to talk about with nullability.
We've pushed it throughout our SDKs this year,
so you get a much better experience
in both Objective-C and Swift.
We highly recommend that you use it
to improve your own Objective-C APIs, particularly
for a much better Swift experience.
Alright, let's come on to the next feature.
This is a big one.
Lightweight generics for Objective-C.
Now, the origin of this feature,
it's actually fairly easy to motivate.
Here we have this NSArray of subviews.
What's in the array?
We don't say what's in the array.
We bring this into Swift and you say, ah, it's an array
of any object, of course.
That still tells me absolutely nothing.
I have to cast a lot.
That's what it tells me.
So we have had, of course, this common request
for typed collections.
Because people really want to say I have an array of views.
I have a dictionary that maps from string keys
over to the images associated with those keys.
This has been probably been the most highly requested feature
for the last decade of Objective-C.
So, now we are finally rolling it
out with lightweight generics for Objective-C.
So this is a general language feature that can be used
to improve the expressivity of your APIs;
it makes collections way easier to use now
that we have all the static type safety of typed collections.
Let's take a look.
So here's our subviews property again.
To make this an array of UI-views,
we just place UI-view-star, so UIV pointer, in angle brackets.
Same syntax you have seen.
The same syntax you have seen from Swift and C++
and C-Sharp, et cetera, et cetera.
Yes, we are completely aware
that angle brackets are quote protocol qualifiers.
Don't worry, we've got it.
So this introduces more type information into Objective-C.
Of course, this reflects into Swift
as much more beautiful type information.
But really I want to talk about the Objective-C effect
because this is a really useful feature for Objective-C.
Because let's talk about type safety.
Here's an example.
So I'm taking the path components of any URL, NSURL.
And I'm putting it into an array of URLs.
That almost seems reasonable if I didn't know this API
and it would be a while before I got the run time error,
the unrecognized selector that points out that no,
I'm completely wrong in my usage of path components.
With type collections and, of course,
us rolling out type collections throughout our SDKs,
now you get a warning to tell you just what you did wrong
at the point where it happens.
Many other cases here say I'm building up immutable array
of NS strings and I foolishly go and add something to that array
without turning it into a string first, okay,
the compiler is going to tell me, no,
you can't put an NS number
into this NS mutable array of strings.
It doesn't make sense.
Now, the compiler actually has fairly deep knowledge
of the semantics here of the Cocoa collections.
So let's take this example here, we have an array of views,
we have an array of responders.
We assign from the array of views to the array
of responders, okay every view is a responder.
This seems fine.
It is okay.
Let's do the same thing with the mutable variant.
So we take the stored mutable array of views and assign it
over to the stored mutable array of responders.
There's a trap here.
The trap, of course, is I can go ahead
and mutate my stored responders, put something
in there that's a responder but not a view.
Now, something later on is getting very, very confused
that the array of views it's looking
at has a view controller in it, not a view.
Compiler understands this is as well.
It will complain at the point of initialization, here,
that while it's perfectly safe to do this kind of assignment
with immutable arrays because they don't change
from underneath you, it is not safe to do
with the mutable variants.
Alright. You have actually seen all you need
to use lightweight generics
and typed collections throughout your applications.
But let's take a look at how we use this
within Foundation itself,
to actually create typed collections.
Because the feature here is generics.
Typed collections is one of the outcomes of it.
So here we have NSArray as you are used to seeing it.
Now we are going to parameterize it,
based on the object type that's stored in the NSArray,
again, using angle brackets.
We are just introducing a name here.
We can use that name throughout the interface, so, of course,
object at index, returns something of the object type.
If we go ahead and add other methods here.
When you initialize with objects the array you get in,
the C-array, contains objects.
Use array by adding object.
You put in a new object, you get an NSArray of objects.
So it composes very, very, very nicely.
Of course this also works for categories and extensions.
Here we have an NSDictionary category, parameterized
on key type and the object type, and we have gone ahead
and added object for key here, takes in a key type,
returns a nullable object type because, of course,
nil matters here and we want to have
that information in our APIs.
Now, of course, there are existing categories defined
on NSDictionary, NSArray, and so on, you may have some yourself.
Those will continue to work as they always have.
They cannot access the type parameters in any way,
but they also won't change behavior at all,
they will continue working as they always have.
That brings me to backward compatibility.
So the entire lightweight generics feature is based
on a type erasure model.
Which means that the compiler has all
of this rich static type information but it erases
that information when generating code.
There's huge benefits here for Objective-C,
that we did not have to make any changes
to the Objective-C run time to make this feature work.
That means we are able to roll out generics
in type collections, you can adopt them in all
of your applications and it does not affect your ability
to deploy back to existing operating systems.
DOUG GREGOR: And if it wasn't obvious from that description,
of course, we are also not going
to change cogeneration in any way.
We are not adding runtime checking to Objective-C
that doesn't make sense in Objective-C.
We just maintain full binary compatibility.
So adopt this feature, enjoy the warnings preventing you
from making horrible mistakes.
And you can adopt it very, very, very...
hmm gradually, I guess is the best term here.
So in addition to binary compatibility,
we want to provide source compatibility,
because we have rolled this feature out through our SDKs.
We don't want you to have to update all of your source code
to use these things everywhere.
We want you to gradually adopt it.
Use it where it makes sense for you.
And so we provided these implicit conversions
in the language that allow you
to add type arguments or take them away.
Okay? Again, there's no run time cost to doing this.
But it lets you get in and get
out of the generic system as you need.
So all of your new code can be written with generics
and if you don't want to touch your old code,
that's perfectly line.
It's not going to change.
We have one last feature to talk about, this one's kind of cool.
So kindof types.
Actually, came out of our work on lightweight generics.
And so we started with, of course,
using the untyped collection here for subviews,
and there's code that may go grab a view
and send some message to it.
This code is fine.
It works today.
We went ahead and did these annotations to say, okay,
subviews contains UI views and now we get some warnings.
The compiler is completely justified
in giving this warning.
It knows now that the first subview is a UI view.
It can't know that you know it's a UI button
that would actually respond to this selector.
And so while the compiler is right,
it's not necessarily useful
to be producing warnings on all of this code.
You get a raft of warnings most of which would be benign
and you would be adding casts everywhere.
This really forced us to consider ID
and how it's used as an API contract.
And so let's make this a little simpler example.
Let's talk about NSApp, which is this global in Cocoa
that gives you access to your NSApplication instance.
Now, what this really means is NSApp is a subclass
But we couldn't describe that to the type system.
With kindof types, we can say this exactly in Objective-C.
What does this mean?
This means NSApp is some kind of application.
So we are going to give it some limited behavior, like ID.
So I have my NSApp, of course I can convert it to an NSObject
because every NSApplication is an NSObject.
The important part here, the ID-like behavior,
is the implicit downcast from NSApplication
to your MyApplication subclass.
We want that behavior because that's how NSApp has
Now, what we won't allow is some silly cross-cast.
You tried to use NSApp in a string?
Well, that's not an NSApplication and never can be.
So you can produce a warning there.
Of course, coming with this is the notion
that you can message NSApp and get all of the methods that are
its superclasses, and its subclasses.
Now, with kindof types we actually found
that this is much more useful than ID.
Because it gives you more type information in the API contract
which is great for both Swift and Objective-C.
So here we have this NS tableview method,
you have column, row, makeIfNecessary.
It's always returned to ID,
because that implicit downcasting behavior
Well, now we can rewrite it as a kindof NSview.
So returning some kind of NSView, and on the Swift side,
ah, now we are returning an optional NSView.
That's the right API for Swift
and it works beautifully in Objective-C.
Let's bring it back to our original example
with lightweight generics.
Here we were with our subviews stated as an NSArray of UIViews.
Well, now we can state that it's an NSArray of kinds of UI views.
So we get the stronger API contract
in Objective-C and Swift.
It's far easier to tell what this property is,
but you don't cause any spurious warnings because you still have
that nice, implicit downcasting behavior from ID.
Hopefully this leads you to a question.
Should I even use ID in an API?
Over the years we have actually been rolling out a lot
of features that give more specific type information
than ID for various important scenarios.
And the same year we introduced Arc,
we introduced instance type,
which says that the method you are calling returns something
of the same dynamic type as self.
This year we are introducing type collections
that eliminate tons of uses of ID.
From our own APIs we have been rolling out these features and,
of course, from your APIs when you adopt this feature.
We now have kindof X to talk about any subclass of X
with implicit downcasting.
So you can keep your code working,
at least all the actually working code that's not doing
weird things, but have a better API contract, and, of course,
protocols have been in Objective-C for a very,
very long time and using ID of some protocol is a great way
to say I don't care what the class type is.
It just has to conform to this protocol.
So there's one major class of uses for ID.
And that's when you really,
really do mean an object of any type.
And there's no static type information that could make
that statement better.
So, a canonical example here is the user info dictionary.
You have string keys and you have ID for the values.
It's completely reasonable
because the different keys will have different types
in those values and it's something you can only
Let's wrap things up.
So, we have big improvements for both Swift and Objective-C.
These languages are codesigned and coevolved
to work together beautifully.
And Xcode and the tools supporting it will help you move
between the two languages, the best way for your workflow.
We have rolled out a lot of great features for Objective-C.
We highly recommend you modernize your usage
These new language features give you much better APIs,
and you will see this in our APIs and in yours,
and give you far better type safety
to catch bugs before they manifest
as the dreaded unrecognized selector at runtime.
And using these features can really make your Objective-C
interfaces beautiful in Swift,
so you have the best Swift experience with your own code.
For more information, please contact our Evangelist,
Stefan Lesser, check out the documentation,
or talk to us in the forum online.
There's a bunch of related sessions talking
about what's new in Swift and Cocoa.
Lots of great Swift sessions here.
Thank you very much.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.