macOS brings many new enhancements such as automatic window tabbing, enhanced color reproduction, and improved presentation of right-to-left languages. Get introduced to new APIs for these features and more, such as NSGridView and NSMeasurement. Learn about new conventions for APIs in Swift and Objective-C. This is your first stop to discover exciting new features in Cocoa sessions throughout the week.
I and my colleagues [applause].
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.
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,
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
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.
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
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
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,
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
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
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
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
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
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
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
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, 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
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
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
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
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
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,
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
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
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
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
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
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
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
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
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 as the user starts to drag, you need to create your promises
and you do that by creating an instance
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,
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.
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
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
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
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
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
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,
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
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.
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.
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,
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
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.
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
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
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
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.
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,
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].
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 --
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
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.
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
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.
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,
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
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.
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,
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.
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
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.
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.
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.
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
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.
again this is API we added last release.
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
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.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.