WWDC2015 Session 401

Transcript

X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> JORDAN ROSE: Good
afternoon, everyone.
My name is Jordan Rose.
(Applause).
>> JORDAN ROSE: Wow.
Thank you.
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
of UIViewController.
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
at developer.apple.com/Swift.
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.
That's fine.
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Which means there's a
whole family of C APIs
that you can now
access directly in Swift
that you couldn't before.
(Applause).
>> 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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
useful information.
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
error domain.
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
(Applause.)
>> 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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
for Objective-C.
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
actually does.
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The other interesting
special case here is
NSError-star-star parameters.
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
around forever.
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
Collections.
Here we have this
NSArray of subviews.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
Whoops, sorry.
(Applause).
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
(Applause.)
>> DOUG GREGOR: And if it wasn't
obvious from that description,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> 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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
All right.
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
of NSApplication.
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The important part here,
the ID-like behavior,
is the implicit downcast
from NSApplication
to your MyApplication subclass.
That's good.
We want that behavior
because that's how NSApp has
always worked.
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
in NSApplication,
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
is important.
Well, now we can rewrite
it as a kindof NSview.
So returning some kind of
NSView, and on the Swift side,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
determine dynamically.
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
of Objective-C.
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
(Applause.)