WWDC2018 Session 209

Transcript

[ Music ]
[ Applause ]
>> Good afternoon.
My name is Ali Ozer.
I, with my colleagues, Chris
Dreessen and Jesse Donaldson,
will be talking to you about
what's new in Cocoa in macOS
Mojave.
As you saw yesterday, we have
some amazing new features in
AppKit this year.
We'll be touching up on many
topics, among which are these.
We'll be talking about some of
the API refinements we've been
doing.
The amazing new Dark Mode, and
related features, some changes
in layer backing, and also
custom Quick Actions.
So, let's dive right in.
Now, as you know, we pride
ourselves on our API's, and our
goal always, is to have API's
that are capable, and
consistent, and powerful.
So, with that in mind, we
continue to do refinements that
improve both the Objective-C and
Swift exposure of our API's.
And, this is not just in AppKit
or Foundation, but also other
frameworks including UIKit, as
you might have heard in this
morning's "What's New in Cocoa
Touch."
Now, the API changes we're doing
are fully source compatible in
Objective-C, and we also expect
them to be 100% migratable in
Swift by the time we GM the SDK.
So, with that, let's look at
some of the API refinements
within this release.
First I'm going to talk about
some updates to string types.
Last release, we introduced
string enumeration types as a
way to collect groups of related
string constants together.
These helped make API's that
deal in these types much
clearer.
And, here are some examples.
The first one is declared as NS
STRING ENUM.
This is used for string
enumerations, where we provide
some values out of the
frameworks with no ability to
extend them, so it's a fixed set
of values.
The next two here, NS EXTENSIBLE
STRING ENUM, this is used to
declare string enumerations
where we might provide some
values out of the box, but other
frameworks and applications can
also add to that set.
So, we've done two changes here.
First one is a simple one.
We've simply replaced NS STRING
ENUM and NS STRING EXTENSIBLE
ENUM with their typed variants.
This is effectively a no-op
change.
These are just more general
forms of the same declarations.
So, no changes in your code, or
call sites, or anything.
Now, the next one, NSImageName,
underwent a bigger change, a
more significant change, instead
of a string enumeration, it's
now declared as NS SWIFT BRIDGED
TYPEDEF, which is effectively a
typedef.
Now, here's what the Swift
exposure of this looks like.
In Swift 4, NSImage.Name came
across as a struct, which is the
way you would declare the string
enumerations.
In Swift 4.2, it's as a
typealias, a simple, good old,
garden variety typealias.
Much simpler.
So, the question is, why did we
do this?
Let's look at a call site
example.
Here in Swift 4 is how you would
take a string, and create an
NSImage with it, by using the
named method.
As you'll see here, you'll be
taking the string, and we're
converting it to an NSImage.Name
into the [inaudible] name before
we call NSImage named.
This does not feel
super-streamlined to have to
repeat NSImage.Name here.
Now, with changes in Swift 4.2,
this is all we have to write.
You do not have to convert to
the NSImage name, which is more
streamlined, a little cleaner,
less redundancy there.
So, we believe this typedef
approach is appropriate for
passed-through values.
[ Applause ]
Yes, we had heard from some of
you.
So, we believe this appropriate
for passed-through values, such
as resource names or
identifiers.
Basically, values that are not
interpreted by the framework but
are just used in a
passed-through fashion.
So, image name, color name,
window frame autosave names, and
so on.
So, these are the types that are
appropriate for this.
Now, note that you still have
the benefits of a specific API
declaration however with this
new approach.
Here's the declaration for
NSImage named method.
You'll note that the argument is
still NSImage.Name, as opposed
to a string.
So, we still have that come
through.
Now, here's the full list of
types.
We did this to NSAppKit.
Turns out a lot of types could
benefit from this.
It's not just this, it's also
this set as well.
So, a number of types have
changed in this fashion.
So, next, I'm going to talk
about common prefixes.
As you've seen in previous
years, over time, we've been
switching from common suffixes,
which is what we used to to many
years ago, to common prefixes in
Objective-C.
Using common prefixes enables
names to group together, and
become more easily discoverable,
and come across better in Swift.
So, let's look at an example.
Here is NSLineJoinStyle as it
appears in the 10.13 SDK.
And, here is how it appears in
10.14.
You'll note that enumeration
values such as
MiterLineJoinStyle now have
become LineJoinStyleMiter.
So, a common prefix.
The Swift exposure changes from
miterLineJoinStyle to just
miter.
So, it's-- you know, you don't
have to repeat the type any
more; it's pretty obvious in the
call site, so much cleaner.
And, so good it deserves a happy
emoji.
[ Scattered Applause ]
Thank you.
And, we did this to a number of
other types that we had not
done, applied this change to,
and here is that list of types.
Next, I want to talk about
formalized protocols.
In the olden days, we used to
use informal protocols, which
are basically categories on
NSObject to group related
methods together.
And, since then, we added
features such as optional
methods on protocols and so on,
and we've been switching to
formal protocols where possible.
And, I'll show you an example of
one of the ones we did this
release.
Here is the method
validateMenuItem, and it used to
be an informal protocol, a
categorization object in 10.13.
Now, it's a formal protocol,
called NSMenuItemValidation,
with .method in it.
The Swift exposure changes from
an extension NSObject to a
formal protocol, of course.
NSMenuItemValidation in Swift
4.2.
Of course, the benefits here are
that objects that do menu item
validation now have a way to
formally declare that they do
that by conforming to this
protocol.
Again, we like this so much, we
did it across a bunch of other
API's.
So, here's the full list of
formal protocols we added in
AppKit.
You'll notice things like color
changing, font changing,
NSEditor, NSEditorRegistration
combines the bindings-related
methods, and so on.
So, it's a good list of new,
formal protocols.
Next, I want to talk about
direct instance variable access.
Now, most-- in our API's almost
all of the instance variables
are private.
And, we've said so, but in a way
that they have been declared,
especially in some older AppKit
classes, subclasses were allowed
to touch the instance variables,
directly access those instance
variables.
Now, some of you may not even be
aware of this, so please don't
go ahead and start using them,
because this is probably an old
code, code I'm sure you didn't
write, but maybe inherited, that
may be using instance variables
directly.
So, for now, we are going to be
frowning upon this practice a
bit more vigorously by
deprecating it.
Now, you'll be-- code that
accesses instance variables
directly will get a warning, and
our intent is to break this in
future updates.
So, as you get the chance,
please go ahead and clean these
usages.
And, the fix is pretty
straightforward.
Instead of accessing the
instance variable directly,
please go ahead and call the
getter, or the property
accessed, or whatever there
might be.
And, if you have some reason to
access the instance variable,
and you don't see a way around
it, you might want to let us
know.
Now, speaking of deprecation,
we're doing one more thing
called formal soft deprecation.
So, over the years we have
deprecated a lot of API's, and
have replaced them with better
ones.
In cases where the deprecation
isn't urgent, we usually go
through an informal deprecation
phase, where we tell you the
API's deprecated, we release
note it, we comment it, and so
on, before we actually mark the
API's deprecated.
Usually to reduce disruption.
But now, we have a way to mark
API's as to be formally
deprecated.
Let me give you an example.
Here we have a symbol,
NSBoxOldStyle, which of course
happens to be a name that begs
to be deprecated.
And, you'll note that we've
marked it as deprecated.
And, the version number for the
deprecation is API TO BE
DEPRECATED.
So, what this does is, it tells
the compiler not to generate a
deprecation warning or an error,
however our intent is that if
you try to use the symbol in
Xcode, or new code, or in access
documentation, you will get a
warning that the symbol is
deprecated, and it will be
pointed at the replacement
symbol.
So, of course, comes across in
Swift as well.
As you can see here, one thing
to note, the version number
100,000.
This is not a pre-announcement,
or a leak of some far, future
SDK.
It's just that's a placeholder
number we're using for now to
indicate this feature.
Now, we use formal soft
deprecation in a few other
cases.
Earlier I showed you this.
And, I told you that we renamed
MiterLineJoinStyle to by
LineJoinStyleMiter.
And, I also said that
Objective-C source code was 100%
compatible.
So, you might be wondering,
well, what happened to that old
symbol that you renamed?
Well, we actually declared that
old symbol, as you see here, by
using this new API TO BE
DEPRECATED.
So, we declare it as deprecated,
as API TO BE DEPRECATED, meaning
any new attempts to use it will
get warnings, but existing uses
will be left alone, because we
really don't want to disrupt
uses of the symbol in
Objective-C source code.
Now, turns out there was a lot
of symbols that were waiting for
this facility, so a lot of API's
are marked with API TO BE
DEPRECATED.
A bunch of these are because we
did the common suffix to common
prefix naming, and some of the
others are symbols that we are
de-emphasizing deprecating,
because we're bringing new ones
in.
Especially in support of
features such as Dark Mode,
which you'll hear about later
today.
So, the last topic I want to
talk about is secure coding.
As you may be aware, we
introduced the concept of secure
coding back in 10.8 and iOS 6.
It basically allows class-- when
you are archiving, basically
allows you to specify what
classes are expected, that way
it can be an explicit error if
those classes are not
encountered in the archive.
Now, the way we did secure
coding, the secure coding was an
optional feature.
But, we now have new API's that
enable both secure coding as a
default behavior, and as a
bonus, they enable error
returns.
Our archiver and unarchiver
API's worked with exceptions,
but of course we prefer error
returns.
And, the new API's enabled error
return behaviors by default.
So, I'll show you the API's
NSKeyedUnarchiver, since that's
the most interesting.
Here is an NSKeyedUnarchiver.
One new method is in it.
It simply creates a
keyedUnarchiver, securely, and
in a way will return errors.
Two other new methods are these
convenience API's,
unarchivedObject(ofClasses from,
and unarchivedObject(ofClass
from.
These basically unarchive a
single object and return it.
They do it securely, and they
will return an error if some
problem's encountered.
Now, note the second method
here.
It's sort of decorated like a
crazy fancy peacock.
All that decoration enables
Swift to infer the return type
much better, which is of course
a trick Swift is really good at.
Now, note that all the way out
at this SDK this year, they do
work back to 10.13, and iOS 11.
So, you can start using them,
even with those deployment
targets.
These methods replace the
methods on this slide here.
Now, you'll note that these are
being deprecated in 10.14 and
also iOS 12.
Since these are not doing secure
coding, we are deprecating them
immediately, rather than going
through that formal soft
deprecation, because we really
encourage you, we really want
you to switch to the secure
coding if you haven't done so
yet.
Now, one more thing about secure
coding is a new value
transformer.
As you may know,
NSValueTransformer is a class
used for automatically
transforming values from one to
another.
These two valueTransformers
here-- unarchiveFromData and
keyedUnarchivedFromData-- the
first one does unkeyed
archiving, the second one does
keyed archiving, but not
securely.
And so, these are now not
working in the way we like, so
we're deprecating these two.
And, replacing them with this
new secure Unarchive
FromDataTransformerName, which
will do the unarchiving
securely.
So, we urge you to switch to
this one as well.
Now, on the secure coding front,
we've also gone ahead and
adopted secure coding in a
number of AppKit classes that
didn't do it yet.
Note here, NSAppearance, which
is a recent, relatively recent
class that is increasingly
becoming your friend, as you'll
see in later talks about Dark
Mode and other features we've
added in AppKit.
We've also added secure coding
to a few foundation API's that
did not have it.
And, here is that list.
Now, one more note on secure
coding.
We have a talk Thursday morning,
"Data You Can Trust," where
we'll talk about doing coding
and archiving and unarchiving in
a robust and secure fashion.
So, I invite you to attend that.
Thursday morning at 9.
So, at this point, the rest of
the talk is going to be about
the new features in AppKit and
related areas.
And, to kick that off I invite
Chris on stage.
[ Applause ]
>> Thanks, Ali.
So, Dark Mode is one of the most
exciting new features in macOS
10.14.
And, I'm sure you all saw
yesterday, I bet some of you are
running it right now.
But, let's go ahead and take a
look.
So, we have these great new sets
of system artwork.
It makes our system UI look
great.
It makes your application look
great.
It's going to make your user
content look great.
And, what we all want to know is
what we need to do to adopt
this.
So, the first step is really
simple.
We need to relink against the
macOS 10.14 SDK.
That's easy enough.
That might be enough for some of
us, too, but most of us are
going to need to do a little bit
more work to make an app that
looks great.
So, the next thing we're going
to want to do, is we're going to
search our application for
places we've hardcoded color
values.
And, we're going to want to
replace them with an
appearance-sensitive color
instead.
For, most system UI elements,
AppKit actually offers a lot of
dynamic system colors that will
react with the current
appearance, and look great for
whatever UI element you're
trying to come across with.
And, to flesh out the list,
we've added even more in macOS
10.14.
But, in some cases you're not
trying to make a system UI
element, you're trying to make
some piece of your document
model that also looks great in
Dark Mode.
Now, you can do this by sorting
your colors in asset catalogs.
So, if you go to the color
editor in Xcode, you can
configure which appearances
you'd like to set up specific
colors for, using the sidebar on
the right.
In this case, we've picked
colors explicitly for the light
appearance, for the dark
appearance, and a general
fallback color for any other
appearances.
Similar to with colors, we're
going to want to go through our
UI's and find places we can use
template images.
Template images are great
because the image artwork will
be tinted with the right color
for whatever appearance we're
using.
And, you might have been skating
by with places in your app where
you included a dark gray piece
of artwork, or solid black
artwork, which looked fine in
light mode, and is going to look
absolutely wrong in Dark Mode.
So, you can make template images
programatically.
You can also set them up in your
asset catalog.
But, you don't need to limit
yourself to template images to
make your Dark Mode UI.
You can also specify colors--
or, sorry, images that look
different in Dark Mode.
In this case, for our planet
app, we decided that we wanted
nighttime view of North America
more in Dark Mode, but for other
appearances, we're going to use
a daytime view.
So, something that's really
great about Dark Mode is how we
handle desktop pictures.
And, let me show you what I mean
by this.
If you take a look at the system
preferences UI, it kind of looks
like it's just a dark gray at
first glance, but it's more
complicated than that.
If we look behind the window, we
can see that we have these
gorgeous sand dunes, and there's
a lot of blues and light and
dark grays in there.
And, if we do the masked pick,
an average color for this
rectangle, we wind up with this
nice dark blue color instead.
So, when we construct our UI and
add back in this gray color,
it's not solid gray.
We're keeping that dark blue
color with us.
And, this permeates even when we
add back the individual controls
in the window.
They all have this nice
character from the desktop
picture.
So, let me show you what this
looks like with a different
desktop picture, in this case, a
flower.
You can see we have these much
brighter purples and greens in
this desktop picture.
And, that affects the system
preferences window here.
Likewise, if we used a red
flower instead, you can really
see in this case, how the System
Preferences window is taking
that wonderful warm character
from the desktop picture and
propagating it to all of the UI
elements.
So, a really common thing you
might be wondering with this is,
that sounds like a lot of work
to dynamically figure out where
a window is, what the average
color is, and you know, update
it live.
So, my first advice to you is
don't be daunted by this task.
AppKit is going to help you.
So, there's some great classes
you're already familiar with
that are just going to do the
right thing out of the box.
And, it's Window, and it's
ScrollView, and it's TableView,
and it's CollectionView.
All of these will look great in
Dark Mode without any changes.
But, if you want to get your
hands on them, you can also
tweak these a little bit.
Each of these classes has a
background color property.
And, there's four very special
NS colors I want to mention, the
control background color, the
window background color, and the
underpage and text background
colors.
And these all, when used with
these classes, get that nice bit
of desktop picture infusion, and
all look slightly different
depending on the role of the UI
element you're trying to
construct.
One other class I really want to
call out for this purpose is the
NSBox class.
If you configure a box as a
custom style, you can use its
fill color property with one of
these special NS colors, or
really any other NS color, too.
But, that's significant, because
NSBox can be used to just add
wonderful color fills to pieces
of your UI, whereas these other
classes are a little bit more
special case.
So, if you really want to get
into detail on this, there's
another AppKit class I want to
mention, which is
NSVisualEffectView.
And, NSVisualEffectView has this
material property that allows
you to determine how the visual
effect you use is going to
process the background behind
it, and what sort of blending
operations it's going to do.
And, we have a few of these to
describe where the
visualEffectView's being used in
your UI.
In macOS 10.14, we've added a
lot more.
So, pretty much whatever sort of
UI you're trying to construct,
we should have a material that's
appropriate for that use case.
In previous OS's, you'll note we
had some materials labeled
explicitly as light or dark.
And, you're going to want to
stay away from those, as they're
not going to look right across
our many new appearances.
So, that brings me to another
topic, which is accent colors.
If we go ahead and look at these
UI elements, we can see there's
this delightful splash of view,
of color, in a lot of these
elements.
And, in macOS 10.14, we've added
a number of new accent colors
for users to select.
And, all of these look
absolutely great.
But, if you're making your own
UI elements-- I'll pause for
applause.
[ Applause ]
Thank you, accent colors.
Anyway, if you're making your
own UI elements, you might be
trying to make this motif
yourself, and incorporate that
splash of color.
So, if you've done that in the
past, you've probably been using
the NSColor.currentControlTint
method, which returns this
enumeration saying whether the
system's running in aqua or
graphite mode.
So, we have way more colors than
that now.
That enumeration's not going to
do the job.
So, in macOS 10.14, we'd urge
you to instead, switch to the
controlAccentColor method on
NSColor.
So, NSColor doesn't stop helping
you with accent colors.
There's a number of other things
it does.
If you're making a UI element,
one of the common features
you're going to want to do is
adjusting the color of that UI
element to reflect user
interaction with it.
So, NSColor introduces a new
method called .withSystemEffect.
And, we've defined a number of
system effects for interaction,
like the pressed state or the
disabled state, and we'll go
ahead and apply a recipe to a
base color to produce a new
color that's appropriate for the
current appearance as well as a
sort of interaction being done
with that control.
So, this will save you the
trouble of having to develop a
formula yourself for modifying a
color for these states.
And, it'll also save you from
cases where you might have a
really long list of hard-coded
colors for different
interactions.
So, it's a great API to make use
of.
We're going to talk about color
for a bit more.
In this case, a new feature of
macOS 10.14, is what we call the
content tint color.
If you look at my mock
application here, you can see
it's mostly user content, it's
mostly text.
But, there's a few elements that
I want to call attention to.
These are things where the user
can click on them to perform
more actions.
And, I didn't want to use the
normal button borders because I
felt that, kind of, overwhelmed
the content.
But, in macOS 10.14, we're going
to let you tint borderless
buttons and image views to call
them out, so the user can still
recognize these as clickable and
interactable.
So, that's really easy to do.
NSButton and NSImageView, both
have a new property called
contentTintColor.
You can set it to any color you
want, to those dynamic colors I
mentioned earlier are great
candidates.
You can also set these up in
Interface Builder.
So, this is what the UI looks
like for configuring buttons.
And, this is what it looks like
for configuring image views.
The tint option is here on the
right, in the sidebar.
So, we've covered a lot of great
stuff about what you can do with
the new appearance in macOS
10.14.
We have more sessions on it, but
they're in the WWDC app, if you
look at our latest sessions.
They're both absolutely great.
Which brings me to my next
topic.
No discussion of Cocoa is
complete without some talk of
layer backing.
So, I wanted to let you all know
that in macOS 10.14, when you
link against the new SDK,
AppKit's not going to use a
legacy window backing store any
more.
It's going to provide all of
this content to the window
server using core animation
layers.
And, a lot of you who do
development on iOS are going to
think this sounds really
familiar to me.
But, let's take a look at what
actually goes on here.
So, if we have a tree of views
like this, in UIKit, the
relationship between views and
layers is really simple.
Every view gets exactly one
layer.
And, the parent/child
relationship between views is
mirrored in the layer tree also.
But in AppKit, we create the
layer tree as a process of-- or
as a side effect of processing
the view hierarchy.
So, we can wind up in cases
where we might decide to take
many views, and use a single
layer for that.
And, that's great because it can
reduce system memory
consumption, and GPU memory
consumption, and also gives the
window server a little less load
to process when it's rendering
the screen.
Something I really want to point
out here, though, is that this
is dynamic based on the
configuration of the view
hierarchy.
So, it can change moment to
moment.
So, you really can't rely on
having this fixed parent/child
relationship between views and
layers like you might on iOS.
So, programmatically one of the
changes you no longer have to
care about here is that you
don't have to explicitly set
.wantsLayer on your views to use
layers anymore.
AppKit will take care of this
for you when you're deploying
against macOS 10.14.
If you're deploying against--
[ Applause ]
In fact, we generally encourage
you not to even use this
property, because if you set it
explicitly to true, we're going
to make sure your view gets its
own layer, and we're not going
to do the optimizations we can
do, where we render multiple
views into a single layer.
You might also need to still use
this if you're deploying to
earlier OS's, but usually you
can still get away with ignoring
it.
I wanted to talk about some
other patterns you might have in
NSView UI's you are making that
use CALayers.
So, one of the easiest ways to
draw a CALayer, is to just
override the draw method in the
CALayer class.
Or, implement a delegate method.
And, this is mostly fine, but
NSView actually gives you a lot
of functionality you probably
don't want to have to replicate
yourself.
If you use NSView's draw method,
it'll go ahead and take care of
things like making sure that the
appearance works correctly for
dynamic colors.
It'll manage the backing store
resolution for you.
And, it's really just as simple
as implementing the layer
methods.
So, I really encourage you to
override drawing at the view
level instead of the layer
level.
Sometimes you'll have cases
where you were implementing the
display method of CALayer
instead, and you're updating
layer properties directly,
because maybe it's more
efficient, or really expresses
what you're trying to accomplish
better.
You can still do that using the
NSView API by overriding the
update layer method, and you get
all the same benefits you do by
using the NSView draw rect
method.
A quirk I want to point out, is
you can implement both update
layer, and the draw methods on
NSView.
If you do this, when your view
has a single layer backing it,
we'll go ahead and use the
optimal layer version.
And, if you're being merged with
other views to save memory,
we'll go ahead and use the draw
rect version.
And, we also use that for things
like printing.
So, it's fine to implement both
of these.
If you have a view that you
really can't express using the
CG drawing API's, or the AppKit
drawing API's, you can, in
addition to the update layer
method, override
wantsUpdateLayer, and if you
just return "true" from that, we
know that you need an explicit
layer to do what you want to
accomplish.
There's another way of taking
best advantage of AppKit and
core animations features here,
and that's just to build your
UI's out of a very simple
vocabulary of basic NSViews.
NSImageView, NSBox, and
NSTextField, these are all
really great building blocks to
make complicated UI's, and
they'll do the right thing no
matter what technologies we pick
to actually render to the
screen.
With our changes to layer
backing, there's a few patterns
I want to call out that aren't
going to work in macOS 10.14
anymore.
If you're using NSView lockFocus
and unlockFocus, or trying to
access the window's graphics
contents directly, there's a
better way of doing that.
You should just subclass NSView
and implement draw rect.
Both of those methods have been
kind of finicky for a while.
So, you'll be saving yourself
some trouble.
The other thing I want to point
out is I've actually written
these in Objective-C, which is a
little weird for a talk that's
mostly in Swift.
And, the really great news about
this is I've never actually seen
any Swift code using these.
The takeaway from that is I
really don't want any of you to
be the first to go ahead and
surprise me.
So, we have one more thing about
our changes with layer backing.
If you're using NSOpenGL classes
to render with OpenGL, and you
link against macOS 10.14, some
of our implementation details
for how we bind the OpenGL
system to our layers are a bit
different.
And, you may notice a few small
changes there.
But, more importantly, I want to
call out that as of macOS 10.14,
OpenGL on our platform is
deprecated.
If you've been using NSOpenGL
view, we really encourage you to
adopt MTKView instead.
And, there's a great session
coming up later today about
adopting Metal for OpenGL
developers.
There's one last change I want
to talk about, which is a change
we've made to font antialiasing.
If you go ahead and look at this
screen comparison, I have macOS
10.13 on the left, and macOS
10.14 on the right.
And, if you look at the text in
this window, it's basically
identical.
But, if we zoom in, all the way
to a 48X scale factor, we can
see that macOS 10.13 is using
this color-fringing effect for
its font rendering.
In macOS 10.14, we no longer use
that effect.
And, this means our text looks
great on a much wider variety of
panel technologies, as well as
scaling modes.
So, we have a bunch of other
great things to cover.
And, at this point I'd like to
invite Jesse onstage to go over
those.
[ Applause ]
>> Thanks, Chris.
Hi everyone.
It's great to see you here
today.
I have a bunch of topics to
cover.
And, I'd like to start with the
user notifications framework.
This has been available in iOS
for some time now, and with
macOS Mojave, we're bringing it
to the Mac.
This allows for better control
of user notifications.
And, it also means that your
apps can interact with them the
same way that they do on iOS.
They should do that using the
NSApplication method,
registerForRemoteNotifications,
as well as the
requestAuthorization method on
userNotificationCenter.
As a part of this work, we're
also deprecating some existing
user notification-related API's.
Specifically, in NSApplication,
we're deprecating the
remoteNotificationType
OptionSet, as well as the
registerForRemoteNotifications
method and the
enabledRemoteNotificationTypes
property.
We're also deprecating all of
NSUserNotification.
So, as you rebuild with the new
SDK, you should try to update to
the user notifications
framework.
Next, I'd like to talk a little
bit about NSToolbar.
When you wanted to center an
item in the toolbar, you've
maybe been tempted to put a
flexible space on both sides of
your item.
And, this works, but it has some
drawbacks.
Notably, when you add extra
items to the toolbar, it'll push
your item off-center.
So, NSToolbar now exposes a new
property, the
centeredItemIdentifier.
You can set this to the
identifier of an item you'd like
to remain centered, and
NSToolbar will put it there.
It should stay there unless
other Toolbar items actually
force it to be out of place.
There's another change here
worth noting as well, which is
that auto layout is now used to
measure toolbar items when the
minimum and maximum sizes are
not specified.
This applies only to apps on the
10.14 SDK, but it means that you
can do things like change the
size of the button, and the
measurement will happen for you.
[ Applause ]
The centeredItemIdentifier
behavior is also available
through Interface Builder.
So, here's the inspector pane
for a Toolbar item.
You can see there's a new
checkbox at the bottom, "Is
Centered Item."
You can click this instead of
setting the property from your
code, and so there's no need to
fall back to the programmatic
API.
You can continue to do all your
UI work inside Interface
Builder.
And, speaking of Interface
Builder, I can't tell you how
excited I am about Interface
Builder's new support for
editing, NSGridViews.
If you're not familiar with
gridView, we introduced it a
couple of years ago, and it's a
layout primitive for rendering
your views in a grid-like
pattern.
This is an example from a
keychain access app.
And, you can imagine how many
little constraints would be
necessary to create this layout
by hand.
You could also build it with
stackViews, but NSGridView makes
the whole thing much easier, and
the new editing support in
Interface Builder is just
fantastic.
Let me show it to you.
So, here's some UI from a
storyboard file.
You can select these controls,
and embed them in a grid view.
And, once you've done that, you
can go through and adjust the
padding and the alignment of the
cells in order to achieve the
layout that you want.
The editing UI works a lot like
the numbered spreadsheet app.
So, you can drag and drop views
into cells.
You can select cells in rows and
columns, and adjust their
properties.
You can even merge cells, as you
see in the bottom two rows here.
Here's an example where we
select a column.
And, this is what the inspector
pane looks like, so you can see
you can adjust the placement of
the cells in that column.
You can adjust the leading and
trailing padding.
If we switch over to the Size
Inspector, you can specify an
explicit width for the column.
Or, if you don't do that, then
the column will be sized
automatically based on the
content.
And, one of the other really
nice things about this feature
is that it's
backwards-deployable.
GridViews authored in Interface
Builder can be used back to
macOS 10.13.4, or if you're not
using merged cells, you can
actually go all the way back to
10.12.
So, if you need to deploy your
app to an older version of
macOS, there's still no reason
to wait to use this great new
functionality.
The next topic I'd like to cover
is some changes to NSTextView.
First off,there's a few new
factory methods.
The first one here, fieldEditor
configures a textView to act as
the fieldEditor for an
NSTextField.
These all provide a much easier
way to configure textViews for
common use cases.
The latter three provide
textViews wrapped in
scrollViews.
This is by far the most common
use case for a textView, but if
you have to do additional
configuration on the textView,
it's important to remember to
look at the scrollView's
documentView.
These are also available through
Interface Builder.
So, again, there's no need to
fall back to the programmatic
API here.
So, let's see what they look
like.
Here's a sample window that
shows all four.
TextViews are sometimes
misconfigured when clients need
to override the fieldEditor in a
textField.
And so, using a fieldEditor
factory method can help avoid
problems there.
The next one, scrollableTextView
should be used for textViews
that are for auxiliary text in
popovers and inspector panes.
Things like that.
And then, the bottom two are for
text that's main document
content.
The one on the left is for rich
text; the one on the right is
for plain text.
You might be wondering at this
point what the distinction is,
because they all look fairly
similar.
The main benefit is that you
don't need to worry about the
system configuration.
For example, if the system's in
Dark Mode, they begin to look
more distinct.
The rich text's textView retains
its white background, and the
plain text turns dark to match
the rest of the system for
example.
So, in general if you use these
factory methods, it'll help keep
your application consistent with
the specifications for the rest
of the system.
The other change to textView
that I'd like to talk about is a
new method for modifying the
text,
PerformValidatedReplacement.
The idea behind this method is
that it gives you a very easy
way to manipulate the text in
the textView, and it gives you
behavior as if the user had
performed the change themselves.
So, it performs all the
appropriate delegate methods, as
you'd expect.
But, the really interesting part
is that any attributes that are
not specified on the input
string are automatically filled
in using the textView's
typingAttributes.
So, let me give you an example.
Here's a window with some rich
text in it, and a little snippet
of code that calls
performValidatedReplacement to
insert the word "Developers" in
the middle.
If we run this, this is what we
get.
The word appears and it matches
the style of the surrounding
text, and we didn't have to
specify any attributes.
There's a subtlety here to be
aware of, though.
And, that's because the fallback
attributes come from the
typingAttributes.
So, if you start with some rich
text like this, and the
insertion point is in the
lighter portion at the end, and
we run the same code; this is
the result.
The style attributes come from
the lighter portion at the end.
So, for this reason, you may
find that you need to set the
selective range for the range
you're about to replace before
you call
performValidatedReplacement.
If you do that, this is the
result that you get.
So, the next topic I'd like to
cover very briefly, is
continuity camera.
This is another fantastic
feature in macOS Mojave.
And, if you're just using the
standard framework classes like
NSTextView, there's nothing
special you need to do in order
to take advantage of it.
So, framework will handle
everything for you.
But, if you have a more
application-specific need for
this, it is possible to use it
more directly.
And then, it's important to
understand that it's implemented
using the existing services
API's.
So, all you need to do is tell a
framework that your responder
class is able to handle image
data.
And, you can do this by
implementing validRequestor.
If you want to try this out, I'd
encourage you to check out the
documentation for validRequestor
and some of the related methods.
Next, I'd like to talk about
custom Quick Actions.
You heard a little bit about
Quick Actions from the State of
the Union session yesterday.
And, they make it very easy to
perform simple actions like
opening a favorite app, for
complex ones like filtering
files, or invoking scripts.
You can build custom Quick
Actions using app extensions or
action bundles from Automator.
They're useful in so many
different places that there's a
variety of ways to invoke them.
But, my favorite by far is the
Touch Bar.
If you put your Quick Actions in
the Touch Bar, it just makes it
very easy to get to them,
wherever you are, whenever you
need them.
And, you can get this behavior
by looking in the keyboard
preferences panel, and
reconfiguring your Touch Bar to
either always show them, or to
flip to them when you hold down
the function key.
Or, you can customize your Touch
Bar and drag the workflows
button into your control script.
It's also worth noting that you
can go over to the Shortcuts
pane, and look under Services.
And, here you can turn them on
and off to control which ones
show up.
They don't only show up in the
Touch Bar, though, as I
mentioned.
So, here's a Finder window for
example.
And, the contextual menu has a
Quick Actions submenu where
you'll see them.
Finder's preview pane also has a
couple of Quick Actions at the
bottom, and then the full list
underneath the "More" button.
And, action bundles from
Automator will show up inside
the Services menu.
So, TrimLogs is one that I wrote
to filter my debug logs, for
example.
And, that brings me to the next
topic I'd like to talk about,
building action bundles, also
known as contextual workflows.
This is a new feature in
Automator.
When you go to Automator, and
create a new document, there's a
new option available now for
contextual workflows.
They look a lot like regular
workflows except there's a new
block at the top that allows you
to configure the input and
output as well as pick an icon
and the color.
So, let's go though a quick
example.
I often have a problem where
there's some file I want to open
in TextEdit, but I can't because
it doesn't have a file
extension.
This is super easy to fix with
Automator.
All you need to do is look
inside the library, and drag out
the Open Finder Items action.
You can configure it to open the
items with TextEdit instead of
with a default application.
Any file selected in the Finder
automatically become the input
to this action, and then if you
save it with some name, it will
automatically show up in the
Touch Bar, or in other contexts
where it's useful.
So, to summarize, we've talked
about a variety of new features,
and other changes that will make
your development experience
richer, and your applications
even more awesome.
Check out the new SDK and begin
implementing some of these
things in your applications.
They'll make your applications
shine, and your customers will
appreciate it.
For more information, you can
follow this URL.
And, also look inside the WWDC
app under this session.
All of the related sessions are
linked there.
Thank you very much.
[ Applause ]