WWDC2016 Session 203

Transcript

[ Music ]
>> Good morning.
My name is Ali Ozer.
I and my colleagues [applause].
Thank you.
I and my colleagues Raleigh
Ledet and Taylor Kelly
from the Cocoa Frameworks
team will be talking
about what's new
in Cocoa this year.
Our agenda is pretty simple.
First, API updates
followed by new features
in AppKit and Foundation.
And in the area of API updates,
we have two main categories
of API updates I
want to talk about.
One, the API changes due to
the new Swift API guidelines
and secondly, the general API
refinements we've been doing.
and secondly, the general API
refinements we've been doing.
So let's get started.
Now as you heard probably
yesterday or if not,
this morning, we have new API
design guidelines in Swift.
And these guidelines still
embrace Cocoa conventions
and practices and
I'll just remind you
of what some of these are.
Using clear and consistent
naming,
striving for fluent usage, you
know, where a call site reads
as an English phrase,
naming mutating
and non-muting method pairs
consistently, sort and sorted,
append and appending, and
avoiding abbreviations.
These are just of the
main guidelines we've had
for many years and
we've documented these
and we've talked about
them in previous WWDCs,
as you see in this session here.
And now we updated
the guidelines
to utilize Swift features
such as strong typing,
type inference, and overloading,
and to make sure our APIs
shine through in Swift.
And let me talk about some of
the key differences in our APIs
as a result of these changes.
For one thing, we're eliminating
repeated and needless words,
For one thing, we're eliminating
repeated and needless words,
which of course makes
our APIs more swifty,
as you might have
heard yesterday.
You saw an example yesterday in
Chris Lattner's section of state
of the union with an example.
Here's another example,
contacts.arrayByAddingObject.
In a method call like this, both
the words "array" and the words
"object" don't really
add much to that call.
So such a name now comes across
as contacts.adding(person).
Here's another example
on the NSColor class.
NSColor.blueColor, now
we're on the NSColor class.
Blue is already a color,
so the word color really
doesn't add much to this call.
So in the new guidelines,
it actually comes
across as NSColor.blue.
But note that we're still
striving for clarity.
Here's another method from
NSColor, NSColor.textColor.
Text is not inherently
a color and, in fact,
talking about the text of
a color could be confusing.
Is it the text that represents
the color's RGB values or what?
So in a case like this, we've
actually left the method alone
So in a case like this, we've
actually left the method alone
and it comes across
as NSColor.textColor,
like it used to be.
Now some of the other key
changes to making use of types,
here's an example,
document.readFromURL ofType,
now this API comes across
as document.readFrom ofType.
You'll note that we've
dropped the word URL
from our method signature.
It's because the type of
the first argument is URL
and with type inference, Swift
knows enough to handle that.
And by dropping that word,
we actually now have three
read methods on an NSDocument
that are all named exactly the
same thing read from ofType
and it's that first argument,
the type of that first argument,
URL data or FileWrapper
that distinguishes
these from each other.
Now another thing to note
here is making use of label
on the first argument.
From here has now been
pulled into the parens.
From here has now been
pulled into the parens.
We do this in a number of cases.
For instance, when the
first argument performs part
of a prepositional phrase,
we pull that phrase inside the
parens, as you can see here.
And you'll probably
see a lot more examples
of this throughout out APIs.
Now you'll also notice that
second argument ofType.
Here we haven't dropped
the word type from the API
because that argument
is a string
and strings are weakly typed.
So we really need a word
to describe their role
and the role here is
that this is the type
of file we're opening.
So there, we keep the
word type in the API.
Now many framework and standard
library APIs have changed
as a result of these
new guidelines
and the importer whose job
is to map Objective-C APIs
into Swift now does it
using these new guidelines,
but you'll note that some
APIs may need further tuning.
We've done that in our APIs,
such as the API textColor,
which I showed earlier,
which is an exception.
And if you yourself have
Objective-C APIs you're exposing
in Swift, you may need to do
so as well by using something
in Swift, you may need to do
so as well by using something
like NS Swift Name, which lets
you override the default choice
the importer is doing.
You also know that the
migrator converts your --
There's a migrator that converts
your existing Swift 2 code
to Swift 3 and it will help
you with all this new naming
in your existing
code, of course.
And the Swift API
Design Guidelines talk,
which took place just before
this one, you can catch this
on video for a lot more details
on these guidelines
and their impact.
Now we have a number of
general APIs refinements,
that some of which
we've done for a while
and others we're
continuing to do.
Let me quickly go through these.
Nullability is something
that we've already
done much of last year.
It's basically declaring whether
arguments, return values,
properties can be nil or
can be optional or not
and we've continued to
refine this, this year.
For instance, here's a method
which in 10.11 was marked
as returning an optional value.
This is addItem on NSMenu
but in 10.12 it's not marked
as returning a non-optional
value because we determined
that this can never really
return nil and it's better
that this can never really
return nil and it's better
to reflect that properly
which makes your code,
of course, a little simpler.
We've been doing properties,
converting getter, setter pairs
into formal properties all along
and this year we're also
actually using Swift's ability
to declare properties
on classes.
For instance, here is a
new property on NSWindow.
You'll hear about this
later in the talk,
allowsAutomaticWindowTabbing.
This is reflected as an actual
class property in Swift.
You'll also note that
we have an ability now
to do this in Objective-C.
You can actually declare class
properties in Objective-C
with this syntax
@property class.
So the same feature comes
across in Objective-C
as well, which is pretty cool.
Here's a Core Data example
NSPersistentStoreCoordinator.
It had this method,
registeredStoreTypes in 10.11.
It's now declared
as a class property.
It's a read-only property,
so it only has a get,
as you can see here.
And in Objective-C,
it also comes
across as property
class, as you can see.
Now generics, we've
been applying them
Now generics, we've
been applying them
to our collections' classes
but they're really, you know,
not just for collections
but they have many
other uses everywhere,
I'm sure as you're aware.
Here's an example from
Core Data, NSFetchRequest.
Here's the way it's declared
in 10.11, pretty simple.
In 10.12, we just went ahead
and added a parameterized
type ResultType.
We also touched a few other
APIs and we added some,
such as this execute method
which returns an array
of that result type.
As a result of this, the use
case now becomes something
like this.
You have a request which you
get from a managed object,
such as employee, and then when
you go ahead and execute that,
your return now is
automatically inferred
to be an array of employee.
Now this is the case
right now but we're hoping
that in upcoming seeds we'll
actually reflect this a little
cleaner like so, which
is actually pretty cool.
So from those two lines, the
compiler is able to infer
that the return type is an
array of that managed object.
We've been improving
our enumeration names.
An example that we've done this
time around is NSColorPanelMode.
The change -- And here's a
use case for it in Swift.
You'll see that's
not very swifty
because .NSCrayonModeColorPanel
is fairly wordy.
The change we've done is to take
the common suffix and pull it
in as a prefix, which
allows the Swift names
to come across a lot cleaner.
You know, where the
point just comes through,
and the use case is .crayon.
Again, this is what
it looked like before
and this is what it looks
like now, fairly clean.
Now in the enumerations area,
we've also now taking advantage
of string enumerations.
Swift supports string-valued
enumerations
and in many cases Cocoa APIs
expose groups of strings
as opened or closed sets of
APIs that we use in our APIs.
And let's look at an example
using string transforms.
In Swift 2 we had a bunch
of global constants.
NSStringTransformLatinToGreek
and so on.
And then we have an API,
stringByApplyingTransform
that took those strings
as its first argument.
In Swift 3 we've actually
added a new type called
In Swift 3 we've actually
added a new type called
StringTransform and then an
extension we declared various
values for that,
such as LatinToGreek.
And the API that takes
that is applyingTransform,
where the first argument is now
an official StringTransform.
So the string argument has
now become StringTransform,
a little more type safe.
Now note that this is an
open-ended enumeration
in that you can declare
your own values.
Let me show you how you do that.
You can go ahead
and add an extension
to StringTransform yourself
and define your own type.
Now the values here are the
values ICU Library accepts
for doing transforms.
So you can use any valid
ID that ICU provides.
It turns out Any to
Publishing is one ICU has
that we don't expose
on our APIs.
So again, go ahead and define
your own publishing transform
and pass it to the APIs just
as if it's a built-in one.
And string enumerations are
also available in Objective-C
And string enumerations are
also available in Objective-C
by using of these two macros
for open or close-ended sets.
And here's the way the string
transform declaration was
in fact added.
In 10.11, this is what we had.
And in 10.12, we have a
new type string transform
which is decorated as NS
Extensible String Enum.
And we're also taking
advantage of Swift's ability
to nest declarations related
about a type, into that type.
An example here from NSData.
We had a option set,
NSDataWritingOptions
and class NSData with an API
writeToURL that used that value.
In Swift 3, this comes
across as class NSData
with a nested WritingOptions,
as you can see here.
And the API that uses
it actually just refers
to WritingOptions, which is
of course much more
cleaner, much better scoped.
Now unrelated to
this nesting change,
you'll note a few more things.
So that's the change
in the type.
You'll also you might note that
we now provide default values
You'll also you might note that
we now provide default values
of an empty set most cases
where we pass options in,
which means you actually
don't have
to pass the options
argument anymore.
You might've also noticed that
NSURL has become URL here.
You might've already heard
about this but we'll talk
about this more later
in the talk.
Now my last topic
before I escape the stage
for now is noescape.
Okay. So noescape indicates
that a closure's execution will
not escape the function call.
What do I mean by that?
Here's a method
from NSCollection view
performBatchUpdates.
It takes two closure arguments.
You'll note that the first
one is marked with noescape.
This means that the execution
of this closure will
finish before this API
performBatchUpdates returns.
The second argument is
not labeled noescape,
which means that the execution
of this closure might happen
after this function returns.
So it's a good hint to
you and so a good hint
for the compiler as well.
This facility is also
available in Objective-C
where we can decorate
closures with NS NOESCAPE
where we can decorate
closures with NS NOESCAPE
to get the same effect.
So that's it for our quick
overview of general API changes.
Now note in the seed you have,
we haven't done everything
we want to do yet,
so there will be some
string enumeration changes,
class property changes coming
in other seeds as well.
So we're going to
apply to more APIs.
So with that, let's talk
about AppKit and I'm going
to invite Raleigh Ledet
on stage to kick that off.
Thank you.
[ Applause ]
>> Thank you, Ali.
Good morning, everyone.
As you can see, we've been very
busy this past year in AppKit.
So let's dive right on in and
talk about window snapping.
So when you're dragging
a window in macOS Sierra,
as you bump up against the
edges will stick at the edges
and as you get along the
top edge of another window
and even during resizing.
So it's now much easier for
you to align windows together
and resize them just the
way you really want to do.
And we spent a lot of effort
here in providing heuristics
And we spent a lot of effort
here in providing heuristics
to make sure that we only
provide the snapping behavior
when that is what
you are trying to do
with your windows
in the first place.
The way you get snapping
behavior in your application is
to just let the system do the
dragging of the window for you.
If you track the mouse yourself
and manually position
the window, you're going
to bypass window snapping and
we will put the window exactly
where you ask us to put it, just
as we have in previous releases.
As you've seen in the keynote,
we now have window tabbing.
This is an example of TextEdit
with three document tabs open.
And the thing about
window tabbing is they are
just windows.
So this example of TextEdit with
three tabs is actually backed
by three different NS windows.
So what we do is every one of
these windows, as long as one
of the tabs is visible,
is considered visible.
So if you check the
NSWindow's .visible property,
it's going to return true.
But only the visible tab
is actually being rendered
to the screen.
We hide all the other windows
at the windows server level
so they aren't rendered
and aren't taking
up resources that way.
And we handle this
all automatically.
So how do you add a
new tab to your window?
You create a new window
and you just order it front
and we will go ahead and create
a tab appropriately for you
and place it in the window.
If you want to remove a tab,
you order your window out
and we'll go ahead
and remove the tab.
This is all done automatically.
Now if the user resizes the
window, we're only going
to resize the window
associated with the active tab.
We don't want to take
the processing time
to manage the other windows
when the users might
not switch to them.
But when the user does switch
to one of the other tabs,
at that point AppKit goes ahead
and resizes the windows
appropriately, re-renders it,
and then changes the
hidden properties
at the window server level,
and so the user gets
the seamless experience
of one window with multiple tabs
even though behind the scenes
we're just dealing
with three windows.
So I want to cover some
areas of what you need to do
in your applications
to adopt tabs
into your applications
depending on what style
of application you have.
If you have for example an
NSDocument based application
or a non-NSDocument
based application.
What you might want to do
if you already have an
existing tab implementation,
and I'll round the section out
with some API that you can use
to customize tabs
in your application.
If you're in an NSDocument
based app,
there's nothing for you to do.
This is fully automatic and,
in fact, in TextEdit here,
we made exactly zero lines
of code changes in TextEdit.
It fully supports tabs and it
just works right out the box.
If you're a non-NSDocument
based app, it's mostly automatic
but what you'll probably
need to do is enable
to New Tab button
in your application.
The New Tab button is
this plus button over here
to the right of all the tabs.
To enable that button, you need
to implement this
newWindowForTab NSResponder
to implement this
newWindowForTab NSResponder
override in your NSWindow
subclass or somewhere higher
up the responder chain.
For example, your
NSWindow delegate
or your NSWindow controller
or your NSWindow document.
If you implement this override
in any one of those places,
AppKit will see it
and will go ahead
and enable the New Tab
button for you automatically.
If you have your own
existing tab implementation,
then you probably want
to disable AppKit's automatic
window tabbing behavior.
There's this class property
on NSWindow
allowsAutomaticWindowTabbing.
This is a class property
early in the bring-up
of your application
called NSWindow.
allowsAutomaticWindowTabbing
equal false
and this will turn off
AppKit's tabbing behavior
and then you can continue using
your own tabbing implementation.
It's important that you call
this early in the bring-up
of your application before you
start ordering windows front.
That's all you really need to do
to adopt tabs in
your application.
It works mostly automatically.
But here's some of the API that
you can use to customize things.
First off, the user can
define some of the behavior
on how they want tabbing
to work on their system
and they can do this in
the System Preferences
and you can find out what
the user preference is
by the class property user
tabbing preferences on NSWindow
and they can set it to manual,
always or to only do tabbing
when they're in full screen.
The rest of these properties
and functions from here
on out I'm going to discuss
are instance properties
and functions on NSWindow.
So once you have an
instance of an NSWindow,
you can set it to tabbing mode.
By default, this tabbing
mode is automatic,
which means we're just going
to follow what the user
tabbing preferences are,
but you can set it to
preferred or disallowed,
depending on your window
type and your needs.
When we group windows together
into a set of tabs, we only want
to group windows that are
similar and the way we do
that is by looking at
the tabbing identifier.
So windows that have the same
tabbing identifier can be
grouped together into tabs.
By default, AppKit will use
a heuristic and try and come
By default, AppKit will use
a heuristic and try and come
up with a tabbing
identifier on your behalf.
We look at things such as
the windows subclass name,
the properties of the
window, the document,
and various few other
properties to try and come
up with the appropriate
tabbing identifier.
This works really well,
but if it doesn't quite work
well enough for your application
or if you want to have
more control over it,
you can set the tabbing
identifier manually
and AppKit will respect that.
You can find out what are the
windows are grouped together
with some instance of a
window together in tabs
by asking for the tab windows.
Note this returns
an optional array.
It can return nil and
it will return nil
if the tab bar isn't even shown
and there are no tabs
associated at all.
And you can manually add
another tab window together
to the group.
Since these are just windows
that explains the API name
where you add a tab window,
instead of adding a tab itself,
you add the tab window
and you order it using
NSWindowOrderingMode and
that will order the tab
NSWindowOrderingMode and
that will order the tab
in relation to the other tabs.
AppKit will add a few
new items to your menu.
Namely in the windows menu,
we add some items to go ahead
and help the user
navigate the tabs,
such as selecting the
next or previous tab.
These are just IB actions on
NSWindow and you can wire them
up to your own user
interface items as well.
For example, you might
want to have a button
that toggles the tab bar.
You just wire that
button up to the window,
toggleTabBar IBAction
and NSWindow will handle
toggling the tab bar for you.
So that's everything about
window snapping and tabbing.
Let's move ahead and talk
about right-to-left support.
We've done a lot
of work in AppKit
to enhance our already
existing right-to-left support.
In the screenshot you can
see here's TextEdit running
in Arabic.
The title bar is flipped.
The scrollers are
flipped to the other side.
Even the new tab button is
flipped to the other side.
And all the little attributes
and the various title bar
buttons are all flipped
appropriately as a
right-to-left user would expect.
I want to talk about
right-to-left support
at three different levels.
What's going on at
the system level,
where the user sets
their localization
in the system preference pane,
how that impacts your
application, and what goes
on in your application depending
on the localizations
that you support.
And then finally down
to the content level,
which is at the NSView level
where you can override
things further if needed
with the user interface
layout direction.
And then I'm going
wrap this whole section
up with a really nice
development tip to help you work
on right-to-left support
in your application.
To start off with, let's
talk about the system level.
The key here is consistency.
We want to have a
consistent appearance
to the user who's running
in a right-to-left system.
So regardless of what
localization you may support
in your application,
we want all menu bars
on a right-to-left system
to start off with the apple
over here on the right
side followed with the rest
over here on the right
side followed with the rest
of the menu items
and this likewise
for the windows title bar.
So the traffic lights
are going to be flipped
over to the other side
and anything that's not
in the content area
is going to be flipped
over to the other side,
regardless of what localization
you have in your application,
providing a consistent
experience to the user.
Now we can't automatically
do this
down into the application
level, because we don't want
to break any assumptions
that your application
might be having.
So it's highly recommended that
you add right-to-left support
in your application, add Hebrew
and Arabic localizations.
And once you have those
localizations in place
at an application level,
all your scroll views will
automatically flip the vertical
scroller and rulers
and NSBrowser will automatically
be flipped as well.
At this level, again we want
consistency so regardless
of what content views user
interface layout direction may
be, we want the scroll
bars to always be
on the same side
for consistency.
Moving down to the
content level,
by default the user interface
layout direction is going
by default the user interface
layout direction is going
to match what your
application is set to.
This is exactly what you
want for almost all cases
but there are a few exceptions,
namely if you have something
like media controls or spatial
controls or time controls
where it is always laid out
the same way left to right
for both left-to-right users
and right-to-left users.
So you can modify the user
interface layout direction.
And the following controls
in AppKit support that.
So auto layout will
not in this seed
but in the upcoming seed two
we'll start using the parent
container to determine what is
the trailing and leading edges.
And already in the
seed, table view
and outline view will flip
their columns appropriately.
NSPageController switches its
animations and the list goes on.
We have a lot of support in
AppKit for right-to-left.
Let AppKit do the heavy
lifting where you can
Let AppKit do the heavy
lifting where you can
and provide your right-to-left
users a great experience.
I promised you a
development tip.
I've been using this
tip all year.
I found it incredibly useful.
In Xcode, you can modify
the scheme of your projects
in the Options section, change
your application language
to right-to-left pseudolanguage.
This allows you to
run your application
in your development language,
and for me that's English,
and so you can see
TextEdit running in English,
but it is all using
right-to-left flipped controls
in it.
So the window title
bar is flipped.
The scroller for the
scroll view is flipped
and you can see all the little
subitems and all the buttons
of the title bar are flipped.
So it's a much easier
way for you to work
on right-to-left support
and make sure everything
is working properly
in your native language.
Now I've just covered what
we're doing in AppKit here.
There's a lot more to
talk about in the What New
in International User Interfaces
talk in Nob Hill on Friday
at 9:00 a.m. They cover
more things on the desktop
at 9:00 a.m. They cover
more things on the desktop
such as WebKit, text
layout, asset management,
and they also cover
right-to-left support in iOS.
So I highly recommend that you
check out this talk as well.
Let's now talk about
promise drags.
If you're not familiar,
a promise drag is
when the user is dragging a
file from your application
but you don't have this
file on disc anywhere yet.
But you're just going to promise
that you'll write it wherever
the user wants to drop it.
That's a file promise drag.
We've supported file
promise drags
in OS X since the beginning.
In macOS Sierra, we're
updating our file promise drag
to be more modern with the
new NSFilePromiseProvider
and NSFilePromiseReciever
objects.
Now these objects allow
file promise drags
to support drag flocking.
If you're not familiar
with drag flocking,
it's when you're
dragging number of items
and they can change
their formation mid-drag,
depending on the
destination application
and what's going on there.
So file promise drags with
these two new classes support
So file promise drags with
these two new classes support
drag flocking.
They're UTI based.
They're completely pasteboard
writer and reader compliant,
which means you can use the
item-based API on NSPasteboard
to work with these objects,
and they're file
coordinated when possible.
So you don't need to worry
about file coordination.
We'll automatically wrap
up a file coordinated read
or write on your behalf.
And they're backwards
compatible.
They're backwards compatible
with the non-item
based file promise API.
And what this means is you only
need to worry about one API.
If you implement an
NSFilePromiseProvider,
you can now provide
a file promise
to anybody that's using the
new NSFilePromiseReciever API
or somebody that an existing
application that's using the
non-item-based API.
They will still be able to
accept your promised file
and likewise with
NSFilePromiseReciever.
You will be able to
accept file promises
from anybody using an
NSFilePromiseProvider
or using the non-item-based
API as well.
So you want to provide a
file promise in your drag,
So you want to provide a
file promise in your drag,
so as the user starts to drag,
you need to create your promises
and you do that by
creating an instance
of NSFilePromiseProvider.
You want to create an instance
for each one of the files
that you are going to
promise and you need
to provide an
NSFilePromiseProvider delegate.
This delegate is what's
going to do the heavy lifting
of writing the files to disc.
At some point the destination
is going to call in this promise
and you'll be asked to
provide the file name
for the destination.
Now you know where the
destination is, you can figure
out the appropriate file name,
but do not write the file
at this point because
it's not wrapped
up with file coordination
yet and we're still figuring
out some of the remaining
items of the drag.
When the drag is completed
and we know all the
information we need to know,
we'll call your delegate back
and ask you to write the promise
to URL and provide a
completion handler.
At this point, it's all wrapped
up with file coordination write.
So just write the file
out to the supplied URL
and call the completion handler
to let file coordination know
that you're finished writing.
If you want to receive
a file promise,
If you want to receive
a file promise,
the first thing you need to
do is register with the view
that you want to allow
the job to occur on.
And this is normally done with
view.register forDraggedTypes
and the drag types you need
to add are the
NSFilePromiseReceiver.
readableDrappedTypes.
It's fairly straightforward.
Now once the user is dragging
a file promise over that view,
you'll start getting dragging
messages and you'll want
to get the promise objects.
So you can use the pasteboard
item-based API and just ask it
to read the objects forClasses
NSFilePromiseReceiver.self
and you'll get an array of
NSFilePromiseReceiver objects.
Once you have an
NSFilePromiseReceiver object,
you can call in the promise
by calling receivePromisedFiles
atDestination options
operationQueue reader.
And it will return pretty
quickly from this function
and your reader block will
not have been called yet.
We're going to call
that back later.
Once the source file has
finished writing all the
promises, now we go ahead and
we call your reader block back
on the operation queue
that you specified.
Now it's important that you do
not specify NSMainOperationQueue
Now it's important that you do
not specify NSMainOperationQueue
for the operation queue
or else you're going
to block your application while
waiting for the source process
to finish writing the files.
And this can take some
time and you don't want
to block your application
during that whole time.
And that's all there is to
do with file promise drags.
It's much simpler API to use
and it works with drag flocking
and supports the item-based
API with pasteboard.
So let's move on and talk
about some improvements we made
to our various container views.
We'll start off with
collection view.
With collection view, previously
when you would scroll,
your contents would scroll
on top of any background view
that you might've had.
Well, now you can tell the
background view to scroll
with your contexts by
setting backgroundViews
ScrollsWithContent to true
and they scroll together.
We also have support
for optional floating
headers and footers.
So you can see the documents
header here becomes floating
and the content scrolls
underneath it.
This is real easy to do with the
NSCollectionView float layout.
Just set the
sectionHeadersPinToVisible true
Just set the
sectionHeadersPinToVisible true
or the
sectionFootersPinToVisibleBounds
true if you want
the footers to float
and NSCollectionView
will then take care
of doing everything
appropriately on your behalf.
You can also optionally
collapse any section
into a single horizontally
scrollable row,
as you can see here, and you get
this nice little carousel effect
whenever you scroll
horizontally.
This is real easy to do with the
toggleSectionCollapse IBAction
on NSCollectionView.
Now the sender of this message
needs to be a view that is
at your section header
or a descendent
of your section header view
and that is how NSCollectionView
can determine exactly
which section needs to toggle
the collapse state for.
Since you have your button in
your header view or descendent,
you should have your
section header
implement NSCollectionView
SectionHeaderView protocol
and that's just to wire
up your button to the
sectionCollapseButton outlet.
Then NSCollectionView will now
be able to find your button
and automatically
hide and show it,
and automatically
hide and show it,
depending on if there
is enough data inside
that section to collapse.
NSTableView will now
reload full width cells
when the column index
is negative 1.
Negative 1 is our magic
number to say a column
that expands all the way across
your table, across all columns.
So when you call reloadData
and columnIndexes includes
the negative 1 in there,
we will automatically reload
that full width cell
on your behalf.
This only works for 10.12 and
later linked applications.
Likewise on 10.12 linked
applications or later,
NSOutlineView will also
automatically reload its cell
views associated with the item
you pass in to reload item.
Additionally, OutlineView now
strongly references the items
you return to it
via the data source.
This is really useful but if
your application really wants
to maintain the original
assigned behavior
that we had previously, you
can set stronglyReferencesItems
that we had previously, you
can set stronglyReferencesItems
to false and return to
the pre-10.12 behavior.
And with that, I'd like to bring
up Taylor Kelly to go ahead
and talk to you about
grid views.
[ Applause ]
>> Thanks, Raleigh.
So the first thing I'd like to
tell you about is NSGridView.
This is a new container view
class, similar to NSStackView
where we completely create
and manage the constraints
necessary to build your layout.
But where StackView creates
a linear distribution of use,
NSGridView creates these
intersecting rows and columns.
You very commonly
see this in something
like a preference pane UI.
Right, there are these
distinct columns and rows
of aligned content
that are self-sizing
and pretty statically defined.
It supports alignment such as
baseline, leading, and trailing.
It supports spacing of the
GridView as a whole as well
as its padding on an
individual row and column basis.
as its padding on an
individual row and column basis.
Similar to a spreadsheet
application,
it supports cell merging.
So a single view can
span multiple rows
or multiple columns.
So for instance these
separators do just that.
It also supports dynamic hiding
and showing of rows and columns
without changing the
GridView's own structure.
So for instance, when we click
on this checkbox, we might want
to hide the Display
Preference button.
And we can do that by getting
the row containing that button
and just setting its
hidden property to true.
GridView will take
care of the rest.
There are several other
improvements we've made
to Auto Layout.
One is a cleanup of overall
AppKit layout cycle meaning
that a view no longer needs
to be using auto layout
or layer backing in
order to participate.
Just by setting needsLayout
to true on that view,
during the next display pass
it'll receive a call to layout.
One implication of this is
that layout is no longer
called twice per display pass
for layer-backed views and we
have less implicit dirtying
of that layout and less
layout passes because of that,
of that layout and less
layout passes because of that,
which is great for performance.
But if you notice that
layout isn't getting called
on your view when you expect,
make sure you're explicitly
setting needsLayout.
All of this makes it easier
to do manual layout
of your subviews.
So you can overwrite
layout without calling super
and instead just
calculate the frames
of your subviews,
set them, and return.
You do want to be sure
that you don't dirty
that view's layout
or other views.
This can happen if during a
view's layout it sets its own
frame or the frame
of an ancestor.
This will dirty that
view's layout
and cause an additional
layout pass.
If this continues, this is
what we call a layout loop
and these are pretty
difficult to debug.
So on macOS and iOS,
we've introduced new layout
loop debugging support
so you can better understand
what view is dirtying layout
and why.
There's changes to the layout
constraint API adding anchor
properties so you
know what anchors
that constraint refers to.
These apply even when you're
not using the anchor-based API.
These apply even when you're
not using the anchor-based API.
In addition with that first
time it is now nullable,
so if you are reading
that property,
be sure to handle the nil case.
In addition, Interface
Builder has new support
for incremental adoption
of auto layout.
So within a single
document or even
within a single view hierarchy
you can partially adopt
constants, which
is pretty great.
NSGridView, the layout
loop debugging and more,
is talked about in Friday's,
What's New in Auto Layout talk.
At this point I'd like
to talk about colors,
specifically wide gamut colors.
So sRGB is a pretty
popular color space.
Usually it's the implied color
space of otherwise unspecified
and most of our displays
have an sRGB color gamut.
The new 5K iMac and
iPad Pro 9.7 inch,
both contain these
updated displays
that can display
more vivid colors.
Specifically, they're
using the P3 color gamut
and this is what we call a wide
color gamut because compared
to sRGB, it can display much
more vibrant greens and reds.
So your applications can display
photos much more accurately
So your applications can display
photos much more accurately
to their original color and they
can display these more vibrant
colors to make UI
elements really pop.
An example of such a color
would be this emerald green,
which happens to be Pantone's
2013 color of the year.
It's outside of sRGB.
So previous displays
couldn't represent this
but it is fully representable
using P3.
Your photos also contain
these more vibrant colors,
especially these
reds and oranges.
A note of irony here is that
the projector and even the video
at home are not actually going
to reproduce these colors,
so you'll kind of have to take
my word that they're special.
If you want to work
with these colors,
there's a new color
space displayP3,
which lets you work with this.
This joins sRGB and
other color spaces.
There's also a new constructor
on NSColor displayP3 red green
blue alpha which allows you
to create a color
in that color space.
UIColor has the same constructor
with the same semantics.
Another way of working with wide
colors is using something we're
Another way of working with wide
colors is using something we're
calling extended range sRGB.
And so when working
with a color space,
you're typically constrained
with component values
from 0 to 1.
And you can pick any color
within that color gamut,
such as this blue,
with those values.
But you can't represent
a color that's outside
of that color gamut.
So sRGB cannot represent
this green color.
Well extended range sRGB
uses the same color primaries
and the same white point as
sRGB but allows the components
to take on values less
than 0 or greater than 1.
So it can represent this
green with a negative red
and blue value and a
greater than 1 green value.
It happens to also be the P3
green primary, so you can see
that with extended range sRGB,
you can represent the full range
of colors necessary
for these displays.
This also has a color
space extendedSRGB
and the existing NSColor
and UIColor constructors
you're already using
that previously gave
you colors using sRGB.
Will now accept values less
than 0 or greater than 1
Will now accept values less
than 0 or greater than 1
and give you back an
extended range sRGB color,
which is pretty convenient.
One important thing to consider
with these wider color
gamuts is color depth.
So sRGB can theoretically
represent any color
within its gamut, but
with 8 bits per component,
you can only address a finite
number of those, right.
The black space here are simply
un-addressable colors using
those 8 bits per component.
When you widen the color gamut,
right, increase the volume
of that gamut but keep
the same bit depth,
you're addressable
color density goes down.
Your ability to specify
a color loses precision.
So this is why we
recommend when working
with these wider color
spaces, such as P3,
that you use 16 bits
per component instead.
It doubles the amount
of memory and storage
but gives you exponentially
more addressable colors.
So we think that
tradeoff is worth it.
What API do you need
to use in order
to consider these deeper colors?
Well, the great news is that
most of it is automatic.
Well, the great news is that
most of it is automatic.
So NSWindow will automatically
use deeper backing stores
with these higher bit depths
on wide gamut displays,
even as you drag
it across screens.
If there's a reason you need
to explicitly control that,
you can set the depth
limit property
to some value of your choice.
Views and layers within that
window will automatically
inherit that bit depth with the
exception being OpenGL view.
There you should use the
associated pixel format API.
CALayer on both macOS and iOS
has a new contents format API
property that allows you
to again explicitly control
the bit depth it uses.
So this is how you
can take advantage
of wide color in
your application.
We've also enhanced part of the
system to better take advantage
of these wider colors.
One example is the color panel.
So on the iMac on the left here,
the color wheel will
actually display, there we go.
It will actually
display and allow picking
from the full range of
P3 colors beyond the sRGB
that normal color wheels allow.
However, you can also
right click the color wheel
and explicitly choose
the working color space.
So even on these
previous displays
that can't render P3 colors,
you can still allow
picking from them.
The RGB color picker
has always allowed you
to choose the color
space you're working in,
but it also allows you to
change the representation
from 8-bit values from 0
to 255 to floating point.
So again you can get this
higher precision when working
with these wider color spaces.
These color panel changes comes
to all applications
completely for free.
No API is needed for those.
The Working with Wide Color
talk on Thursday covers this
and more, such as asset catalog
support and WebKit support.
I'd recommend checking that out
if this stuff interests you.
So the next topic is
status item enhancements.
So status items are
the things that live
in the upper trailing
corner of the menu bar
and these are things that
previously required the use
of private API to achieve
but now come mostly for free.
First is reordering.
You can now command click and
drag on any item and reorder it
within and beyond
the system items.
You can also use keyboard
focus to navigate to your item
and even activate
menu items within.
The best part of all of this is
that this comes completely
automatically
with no API opt-in
or link check.
So all items are command-click
and drag to reorderable,
and any items with a
menu set will participate
in keyboard navigation.
If they have a custom
target action,
they'll just be skipped over.
The next is hiding and removal.
You can now command-click
and drag an item
out of the status bar, remove
it, get notified of that change,
and even programmatically
restore it.
Unlike reordering, this
does require opt-in.
No status items will be
automatically removable
and you can do that by setting
the behavior of the status item
to include removalAllowed.
You can programmatically
read/set
and even get KVO notified
of this change using
the isVisible property.
And if your application
is a status bar app,
meaning its only representation
is that icon in the status bar,
meaning its only representation
is that icon in the status bar,
there's no doc icon or other
way to quit it, you can set it
to automatically quit on removal
by setting the
terminationOnRemoval behavior.
All of this gets autosaved
for you, the location
and the visible state so you
don't have to worry about trying
to preserve that using
the autosave name.
We automatically generate
this based on the item index
that you created in
your application,
but if you create them in
some non-deterministic order
or just want to have
more explicit control,
you can set that autosave name
to some identifier
of your choice.
So that's status
item enhancements.
A lot of it comes for free, and
with a little bit of tweaking,
you can really make them
great in your application.
Next are control constructors.
So these are new constructors
on existing NS Controls
that make it really easy to
get standard look and feels.
Examples are different types
of buttons, segmented controls,
image views, sliders, and
labels, and text fields.
So these are the types of
things you're already working
with in the Interface
Builder object library
and it makes it just as easily
to use these right
out of the box.
They come with the
standard system setup,
the right font size,
and text color,
and they support
different contexts.
So the label here looks
great in aqua, vibrant light
and even a vibrant dark
all right out of the box.
There's no additional
setup needed.
I'd love to show you an example
of what this does to your code.
So this is creating
a checkbox before.
There's quite a few
properties to set
and the unfortunate thing is
we really only care about three
of those; the title,
target, and action.
Well with checkbox, title,
target, action, it's distilled
down to just that,
which is pretty great.
A bit more of a --
Oh [applause].
Just wait.
So this is creating just
a static label, right,
just some text on the screen.
And here, we care about
just the string value.
Well, with labelWithString,
it again is just that.
So, this is pretty great.
It comes out of the box --
[ Applause ]
It comes out of the box
ready to be used with
or without auto layout.
So if you are going to be
positioning with constraints,
you still need to set
translatesAutoresizingMask
IntoConstaints to false,
like all of your other views.
And so if you already have
categories doing these kinds
of things, we still
recommend moving
over to these new system
ones because you'll ensure
that your controls
have the standard look
and feel both now
and in the future.
The last thing I'd like to
talk about are API refinements.
I only covered a number of
these that applied to all
of our frameworks and these
apply to AppKit as well
but there's two more that I
want to talk about that apply
to AppKit specifically.
The first is weak delegates.
So we've added new zeroing
weak delegate support
for various delegates and data
sources for different classes,
so you no longer need to clear
these properties once the
delegates is deallocated.
It still supports non-weak
referenceable objects
in which case it'll fall
back to the existing assign
or unsafe, unretained semantics.
We've also gone through
and made sure that all
of our classes explicitly
did declare their
of our classes explicitly
did declare their
designated initializers.
These are the same as what they
effectively were previously
but now are just
declared in the actual API
with the one exception
being NSCursor.
So if you are subclassing
NSCursor,
please see the release notes
for how you should
properly deal with that.
As with all newly declared
designated initializers,
you should make sure that
you're properly dealing
with that in your subclass.
And so if you weren't
previously,
you potentially had these
incorrectness issues
that maybe were subtle bugs.
In Objective-C, you'll now
see build warnings for this.
And in Swift, you're going
to get build failures.
So you want to make sure
that you're properly handling
these different cases.
So that's it for
what's new in AppKit.
At this point, I'd like to turn
it back over to Ali to tell you
about what's new in Foundation.
[ Applause ]
>> Thank you, Taylor.
So here are some of the things
that are new in Foundation
and let me just dive right in.
Now earlier you saw
NSURL becoming URL
Now earlier you saw
NSURL becoming URL
and I think we also talked
about it a bit yesterday.
We are dropping NS prefix in
key Foundation types in Swift.
Now, as you might
know, large subset
of Foundation actually ships
with the Swift Core Libraries
as a part of Swift Core
Libraries and is available
in other platforms,
such as Linux.
And we want to match the naming
style of this part of Foundation
with the convention established
by the Swift Standard Library
which does not use prefixes.
As a result, a lot of our
types drop their NS prefixes
in Foundation and
Swift, as you can see.
NSFormatter becomes
Formatter and so on.
Now the last two here,
NSData and NSURL are part
of a special category and I'll
mention these in a little bit.
Now, this is happening
in Foundation only.
It's not something
we're applying
to our other frameworks,
and even in Foundation,
it's only applying to some APIs.
We do not apply this
NS dropping to APIs
that are inherently
tied to Objective-C.
Examples are NSObject,
NSProxy, NSAutoreleasePool.
Examples are NSObject,
NSProxy, NSAutoreleasePool.
We also do not apply it to
APIs that at platform specific
and are, in fact, not
available on other platforms
such as NSUserNotification,
NSXPCConnection.
And in one other case is classes
which are also exposed
as value types.
So here we are exposing
data, URL, et cetera,
but we're also exposing NSData,
NSURL, and so on and let me talk
about what I mean there.
Now first let me explain
a bit about value types.
You might already be
familiar with value types.
We've had this concept in
Foundation for a long time.
These are types where value is
important, not the identity.
Examples are NSString,
NSData, URL, Array, et cetera.
Now, since a number
of Foundation APIs already have
these value type semantics,
we've gone ahead and added
them as value types in Swift.
And here is the full set of
APIs where we've done this.
This is in addition of course
to string, array, dictionary,
This is in addition of course
to string, array, dictionary,
and set which are already
exposed as values types
in Swift, since they're
available
in the standard library.
So now these types here are
exposed as structs in Swift
and they have value
type semantics,
meaning they can be
directly mutated,
if mutability makes
sense for them.
You can use let or var on these
to distinguished mutability
at the time you declare them.
These also conform to the
expected Swift protocols
as well, as you might expect.
Now existing class APIs
still remain in cases
where we've created
these value types
and let me look at
a case study here.
An example is data, the
one I already mentioned.
So now we have the
struct data type.
This is the value type for data.
This is the data
type we expect you
to use most often
in your programming.
This is the type moving forward;
however, we also have NSData
which is a subclass of
NSObject and NSMutableData
which is a subclass
of NSData itself.
Now NS types remain
because something
Now NS types remain
because something
like NSMutableData is not
migratable very easily,
so the migrator will
not migrate it.
Another reason we have NS types
is sometimes you actually do
want to subclass these types.
You know, you might
be subclassing NSData
or NSMutableData to provide
some specialized implementation
and you can do that
with, of course,
the class types,
as you see here.
So these are some of the reasons
why the NS types still remain.
Now, let's look at
some differences here.
The NSData class has
a length property.
This has been named count
in the struct version
because it's more
consistent with the rest
of the Swift Standard Library.
Methods such as write
to, range of and many
of these other methods
remain pretty much intact.
They come across the same
way except you'll notice
that the NSRange and NSData
has become range of index
in the struct data version,
which is more consistent
with the Swift Library.
And finally you'll note that a
mutating function, like append,
is not available on this
value type data directly while
in the case of NSData, it's
on the NSMutableData class.
in the case of NSData, it's
on the NSMutableData class.
So these are some of the
differences you'll see
between the value types
and the class types.
Now I'm not going to say
much more about this.
There is a talk this afternoon,
What's New in Foundation
for Swift in the Mission room.
I encourage you to attend that
and hear more about these.
Now we have several
new types in Foundation
to represent measured amounts.
The main class here
is the unit class.
This is an abstract type to
represent units, such as miles,
degrees Celsius, kilometers
per hour, and so on.
And then we have
a class dimension,
which is a subclass of unit.
This represents unit
families such as length,
temperature, and
speed and so on.
So here we have the unit class.
We have the subclass dimension
and then we have subclasses
such as unit length,
unit temperature,
unit speed, and a bunch more.
There's a helper class unit
converter that allows conversion
between units within
the same unit family
and there is a struct
measurement, it's a class,
of course, in Objective-C but
across as a value type in Swift,
of course, in Objective-C but
across as a value type in Swift,
struct measurement which
combines a value such as 10
with a unit such as miles,
so this basically is
now a measurement,
and finally the icing
on the cake,
we have the measurement
formatter class
which will take one of these
measurements and show it
to the user in the
user's locale.
So it'll show 10 miles to a
user here in the United States
but will show 16 kilometers, for
instance, to a user in Europe,
who's using the European system.
So it will do the
conversions for you
and show the user
the right thing.
[ Applause ]
Now out of the box, we have
plenty of unit families defined.
Here's the whole set.
So these are subclasses of
dimension, and within each one
of these unit families,
we actually have multiple units
defined out of the box as well.
Let me take a look at unit
temperature for instance.
You'll see that unit temperature
has three standards units;
kelvin, Celsius, and Fahrenheit.
And these are defined
as class properties
on the UnitTemperature
class and many
on the UnitTemperature
class and many
of the other dimensions also
have a number of units defined
that know how to convert
between each other.
And even better news, you can
actually add your own units
on top of what we
provided and they'll play
with what's already there
and you can also add your
own unit families as well.
So you can hear much more
about this Friday afternoon
at 4:00 o'clock,
Measurement and Units.
DateInterval is a new type
we've added to Foundation.
It represents a date interval.
It's got three properties;
start, end, and duration.
Fairly straightforward, so
these are not, of course,
fully independent
but they're reflected
as three separate properties.
In addition to these properties,
DateInterval knows how
to do things like check if a
date is within a date interval
or whether two date
intervals overlap and so on.
Date intervals are of course
also very useful to be formatted
with the DateIntervalFormatter
class.
That's something we -- That's an
API we introduced last release.
We had an API string from to.
Now we have the string from API
which simply takes
a date interval,
so fairly straightforward.
Now at this point let me
give you a public service
announcement about
handling dates and times.
So handling dates can be tricky.
Now this is not relationship
advice here.
Okay? I'm not a doctor.
Let's say you want to
represent a ten second period.
You might go ahead and create
a DateInterval like this,
start date and a
ten second period.
This is likely correct for
whatever you might try to,
whatever you're trying to
do with a ten second period,
but let's say you're
trying to represent a day.
You might go ahead and
write code like this,
24 times 60 by 60 which is the
number of seconds in a day.
Well this is the number of
seconds in a 24-hour period
and it's often not
going to be correct.
The reason is because days
are not always 24 hours long.
Months aren't always 31 days.
Years aren't always
365 days and so on.
Years aren't always
365 days and so on.
We always keep those in
mind but there are also days
which are 23 hours or sometimes
24 hours, 25 hours, as you know.
So depending on what
you want to do
with a DateInterval representing
a date, are you trying
to set an alarm exactly
24 hours from now?
Are you trying to send an alarm
at the same time the next day?
You have to be careful.
Typically the correct solutions
here involve using the calendar
class and you can hear
about these problems
and also luckily their solutions
in this talk from 2013,
Solutions to Common Date
and Time Challenges,
which I encourage you
to go back and watch.
ISO8601 DateFormatter is
another new API in Foundation.
It's a formatter for dates.
Thank you.
[ Applause ]
So clearly some of you have had
to use 8601 before;
8601 is a standard.
It's an interchange
format for specifying dates
in an unambiguous manner.
So this is a separate
class than DateFormatter
because unlike DateFormatter,
which is meant
for user-localized dates, 8601
formatting is non-localized.
for user-localized dates, 8601
formatting is non-localized.
It's, you know, interchange
format.
So it's a separate type.
We decided to keep
things simple.
Using it is very simple.
So create a formatter.
Get yourself a date, again
not relationship advice.
And simply ask the formatter
for the string for that date
and it will return
you the format.
Now this DateFormatter
can actually go both ways,
so you can actually -- Oh,
by the way, here's the output
from that call, and
as you can see,
it's getting close to lunchtime.
And here is -- This formatter
also goes the other ways,
also does parsing.
So you can get yourself a
formatter and ask for the date
from a string and it'll
return the date for you.
So it goes both ways.
Now by default, this will do
RFC 3339, which is one format;
however, there are options
that let you specify some
of the behaviors,
if you need to.
Now quickly let me cover
some other Foundation updates
we have.
URL has a bunch of
new properties,
URL has a bunch of
new properties,
such as canonical path of
a file and a bunch more,
like whether a volume
is encrypted and so on.
You can read all about
these in the release notes.
There's a new class
URLSessionTaskMetrics.
This class helps you gather
network resource loading
performance information
so you can actually look
at the network performance
of your applications.
PersonNameComponentsFormatter
is an API we added last release.
As you know, it takes a
person's name and it formats it
in a locale-appropriate manner.
Well in this release, it
actually can now parse names.
So you give it a name
and it will return
to you the first name,
last name, et cetera
and it does a pretty good job
since it uses a statistical
model based on real-world data.
And finally -- But there are
some tricky names out there.
So don't get your
hopes up fully.
And DateComponentsFormatter,
again this is API we
added last release.
In addition to the full
style and the short style,
In addition to the full
style and the short style,
we now have a brief style
of date that you can format.
And next release, maybe we'll
add the boxer style as well.
Okay, so that's it
for Foundation.
Core data, just a quick
mention of core data.
You already saw some
API improvements
in core data with generics.
There's a bunch more
new APIs in core data,
such as generational querying,
persistent store description,
the NSFetchedResultsController
class is now available in OS X
as well, I'm sorry,
macOS as well.
You can hear all
about this Friday
at 10:00 a.m. What's
New in Core Data.
And one more talk I want
to give a shout out to,
every year we get up here
and tell you about new APIs,
new technologies were introduced
and you might not always be
in a position to adopt
these APIs because you're
in the middle of something else
or maybe you wait a
release and so on.
Well, if you want
to get an overview
of recent APIs we've
added, APIs are important
to create modern
applications for the Mac.
This is talk for you.
It will cover a lot of topics
and they'll have pointers
to other sessions of
interest, not just in this WWDC
to other sessions of
interest, not just in this WWDC
but also prior WWDCs as well.
It's also appropriate
for everyone, all ages,
all experience levels.
It's also Friday
at 5:00 o'clock.
So I hope you're here.
Okay, so and here is
the webpage you can go
to for more information.
Please read the AppKit and
Foundation release notes,
which you can find in
our developer tool site.
It's there, just raw
information about a lot
of the stuff I talked about.
Here are the related
sessions we mentioned.
There are of course many more.
Thank you very much.