Video hosted by Apple at devstreaming-cdn.apple.com

Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2019-210
$eventId
ID of event: wwdc2019
$eventContentId
ID of session without event part: 210
$eventShortId
Shortened ID of event: wwdc19
$year
Year of session: 2019
$extension
Extension of original filename: mp4
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2019] [Session 210] What’s New ...

WWDC19 • Session 210

What’s New in AppKit for macOS

Frameworks • iOS, macOS • 37:02

Learn about the latest APIs in AppKit and associated frameworks. Get an overview of the enhancements coming in macOS Catalina to help you save time, take advantage of the latest hardware, and add polish to your application.

Speaker: Chris Dreessen

Open in Apple Developer site

Transcript

This transcript has potential transcription errors. We are working on an improved version.

Hello, and good afternoon. I'm Chris Dreessen. I work on the Cocoa frameworks. And we're going to be talking about what's new in AppKit this year. So let's dive in. We have a lot of functionality. We have some additions to NSColor. Some additions to NSScreen. We have a whole grab bag of features to help you with text and fonts.

We're going to do a little pub crawl right here in this session. And we're going to talk about Toolbar and Touch Bar and Sidebar. And then, we're going to talk about some new control functionality in AppKit macOS 10.15. And we'll wrap up our section on AppKit by talking about NSEvent. And we'll take a small jump and go into some Foundation features. Including some geometry enhancements and new formatters to make localization easier than ever. And then we'll wrap things up with some notes on system extensions in macOS 10.15.

So before we do that, though, let's go ahead and address the big thing. In macOS 10.15, AppKit is not the only UI framework on the system. We have two new UI frameworks joining us. So one of these you've probably already heard of, and that's UIKit. In macOS 10.15, you can recompile your apps and run your iPad apps on the Mac. And if you have a well-maintained AppKit app. This is probably not going to be very interesting for you.

But if you have an iPad app you've never brought to the Mac. Or you've had an iPad app you've been investing a lot in the last decade and not so much the Mac. This could be very neat. You will still use AppKit to add the finishing touches to your UIKit app for things like Toolbar and Touch Bar support. But we think that can be very interesting.

The other new framework. And we're really excited about this. Is SwiftUI. And SwiftUI is this neat, declarative way of describing your user interfaces. And the transitions between them. Ways of binding them to your model data. And this, we think, is a great way for making you UI's. It's Swift native and supports all sorts of Swift language features that we really like. Again, this is something you will use in conjunction with AppKit. You will embed it in view hierarchies potentially all over the place. So there's sessions about both of these frameworks all throughout the week. And we think you'll enjoy them.

Onto AppKit. So in macOS 10.15, we have some new system colors in NSColor. We have teal and indigo. These are system colors, which means they're actually dynamic. Depending on which appearance you use, they can look differently. But we think these are great colors. And you'll enjoy using them in your apps.

We also have an under-the-hood change in NSColor we want to talk about. And that's that NSColor is now using the tagged pointer system. We also use for NSNumber and NSString. And what is a tagged pointer? Well, normally, for an NSColor, we would store the various component values or other information as iBars in an allocated object.

And with tagged pointers, we instead condense that information down to a smaller number of bits and store it in the pointer itself. So there's no separate allocation. If you had code that was very heavily allocating or deallocating NSColors you're going to notice a performance win from this. So we're excited here.

Generally, that's going to be an invisible change for you. But there is a case I want to point out. If you're accessing a derived property of the color, for example, the CGColor, with a non-tagged version, that could be cached as an iBar in the color. And it's possible the CGColor would live as long as the NSColor.

In the snippet we have on screen, you could see that we passed that CGColor to a context set fill color with Color Call. And that would have worked okay in the past. With tagged pointers, using it outside the auto release pool is potentially hazardous. So good hygiene not to do that anyway. But something to be aware of just in case.

So a lot of us have used the Color Panel. And there's a near and dear to us eyedropper tool in the Color Panel that lets you click it and bring up a magnifier like this and then select a specific color on screen to read the RGB values of. In macOS 10.15, we're exposing this functionality to you too with a new class called NSColorSampler.

So NSColorSampler is very simple. It has a single-class method on it called Show. You pass a block to show and we will call you back with the selected color, or null if the user cancelled out of this, and we're really excited to share our implementation with you, too. If you have your own implementation, something to be aware of in macOS 10.15, is that screen recording is going to prompt for user permission. And this is something that doesn't happen if you use NSColorSampler itself.

There's another NSColor API that we find incredibly useful. We call it the Dynamic Color Provider. And it's really just a new initializer on NSColor. It takes two arguments. One of these arguments is a block. And that block accepts an NSAppearance. When we go to resolve the color. Either because we're drawing it in a bitmap context, or writing it to a file, or using it as a layer background color, we're going to call this block with whatever appearance is appropriate at the time.

In our snippet on screen, we use the NSAppearance best-match method to tell us whether the requested appearance was more like aqua or more like dark aqua. And we have hard-coded colors for each of those cases. This can be very useful where you want to have some programmatic decisions and dynamicism in your usage of NSColor in your application. And this is much simpler than trying to propagate a hard-coded literal color across the view hierarchy on appearance change.

So I mentioned there were two arguments. The other argument is a name. And the name is very significant for coding purposes. If you send one of these colors over an NSConnection, NSXPCConnection. When we decode it, we're going to look it up by name. So it's also important to have registered that color on both sides of the connection.

So colors are great. NSColor is great. And they're all better with screens to view them on. So we'll talk about some NSScreen improvements. If you've ever implemented a screen picker control, you may have wanted to have a user-facing string to identify an NSScreen with. And if you use the inherited description method from NSObject, your users probably were not content with NSScreen 0x60000261e460. So in macOS 10.15, NSScreen.localizedName will give you a nice, human, readable string to describe that screen.

All right, talking about screens more generally. Over the last many years, screens have been getting brighter and brighter and brighter. And there are very few people who run their screens at max brightness anymore. And if we apply this to a specific picture, we can imagine that black is a zero component value and one is the white component value. And as we dim that screen, we're sort of compressing what ones means in absolute terms. We are emitting fewer photons per unit value in our software.

But that monitor hasn't lost that ability to produce bright colors. We can instead allow Extended Dynamic Range content. Content that isn't clamped in the zero to one range. And keep using the maximum brightness potential of that monitor. To make some images where we have things brighter than our referenced white point.

And this isn't actually a new feature. This is something you've been able to do on a number of Macs since macOS 10.11. There's two API's that would help you do this. One of them is NSScreen.maximumExtendedDynamic RangeColorComponentValue. It actually does stuff. It's not just the longest Objective-C property name you've ever seen.

[ Laughter ]

And what it would do is when your system was in this Extended Dynamic Range mode, it would go ahead and tell you the maximum component value you could use before clipping would happen. So that could be 1.3, for example. If the system wasn't in this mode, it would just return 1.0. So you'd put the system in this mode using a different API and that's CAMetalLayer.wantsExtended DynamicRangeContent. There is also an API in NSOpenGLView called wantsExtendedDynamicRangeOpen GLSurface. And when either of those is set to true. You can get that extra headroom from this API.

So something we've added macOS 10.15 is an even longer Objective-C property name. The important bit is actually shorter. That's this maximumPotential piece. And this will tell you that headroom, that maximum value. Even if the system isn't in this Extended Dynamic Range mode. And that can be very useful.

If you are working with Extended Dynamic Range content. You might have multiple possible pipelines you can send your image data through. And a floating point pipeline for extended content is probably more expensive than a BJRA pipeline, for example. So knowing that you have that headroom to play with ahead of time. Can let you conditionalize that support.

So there's another API I want to talk about. Specifically, for the new Apple display we saw yesterday. And that display is absolutely amazing. Because of how bright it can get. It can sustain 1000 Nits indefinitely. And because of that ability, we like to say it's a reference quality display. We can say that for a specific component value. There will be an absolute number of Nits for that pixel. Now, it's very bright. But it's not infinitely bright.

If you go ahead and produce a bright enough pixel value, it won't actually be able to represent it. And that reference quality attribute we talked about will be compromised. We'll have to scale the image content down to fit in the brightness range available. And that's what NSScreen maximumReference value is telling you. If you exceed this value, you're not going to be able to dish out absolute Nits anymore.

Okay, so I mentioned see CAMetalLayer as part of a way of getting an Extended Dynamic Range content. And I want to point out something that if you're using MetalLayer on the Mac today, you should be doing. And that's you should be paying attention to which screen and which Metal device your CAMetalLayer is going to be displayed on. That's a little convoluted. You have to get your window and your window's screen and your screen's device description.

And then you have to ask it for this hard-coded string that you found in our documentation. But we never export it in any of our headers. And finally, you'll pass that the CDDirectDisplay to figure out which device to use. And it's worth it because that will allow you to avoid moving the data between GPUs across the system bus.

But we've made this better in macOS 10.15. CAMetalLayer and MetalView have a new preferred device property that will answer that question for you. It really reduces your code around this. So we're excited that you get to use that this year. And that covers what we wanted to say about screens.

And now we're going to go into a whole diversity of text features. The first of these I want to mention is NSTextView uses adaptive color mapping for dark appearance. And this is a feature that you can turn on and off in Text Edit. I have snapshots of it in both aqua and dark aqua appearances. Using colors from the system crayon picker. And you can see that when this feature is activated, snow and licorice, for example, almost invert colors. Meanwhile, the more saturated and vibrant colors retain that same color character. But change brightness to better match the appearance they're in.

So this can be very useful for making text use with playing content where you want them to fit in with the current appearance. And it can be very useful for Rich Text documents where that desire to make them fit in is more important than making them appear exactly as they will on a printed page, for example.

Generally, we think this is the right thing to do. But if you have an app that's focused around authoring Rich Text content. You probably want to either opt out or offer the user the ability to turn this off. So they can decide that they want a representation matching printed content more than their screen.

So I think most people in this room are familiar with NSSpellChecker. If not as a developer, then as a user. And in macOS 10.15, we're happy to announce that NSSpellChecker has a successor. And that successor is NSTextCheckingController. So NSSpellChecker worked within a text view. But NSTextCheckingController works with a variety of systems. We use it in UIKit, and WebKit, and AppKit. And you could use it yourself by implementing the NSTextCheckingClient protocol.

But in addition to spell checking, it does other things. It does grammar checking. It can do data detection to find URLs and phone numbers and dates. And you can control all of that and configure whether it's going to merely highlight misspellings or automatically correct them. So we think it's a very flexible API.

And if you're big on text input, it's something worth checking out. A small addition related to text is that almost all of the NSText-related classes support secure coding now. So if you wanted to use these as part of the vocabulary of -- over an NSXPC connection, they will work splendidly.

We're probably all familiar with NSFont. And slightly fewer of us are familiar with NSFontDescriptor. And NSFontDescriptor is a neat class that lets us look up and transform fonts using sort of semantic attributes about them. So I've made a little sample app here. And the top row is a font. I've hard-coded in Interface Builder.

But the subsequent rows, I've configured using the SNFontDescriptor System Design API, which is new in macOS 10.15. And Latin [inaudible] lets me go ahead and say. "I want to switch to a rounder font, or serif version, or a monospace font." And there's a session about this. Which will go into much greater detail about it. But we think this is a great way of stylized your applications.

So if anyone has a cross-platform app, where they are writing Rich Text documents on both Mac OS and iOS, or even an app that's not cross-platform where they are reading documents from the other platform. You may have hit a situation where even though the document is specifying the same font sizes. They visually look very different. And that's because we have very different screen densities between our iOS devices and Mac devices.

In macOS 10.15, we have new attributed string API's that you can use when reading and writing attributed strings to Rich Text documents. And you can tell us what the source and destination operating systems are and we will automatically adjust font sizes to make them appear visually the same. In this case, we brought 160-point font down to 120 point. Which is roughly where they're visually the same height.

The last text feature I want to talk about is in addition to NSLayoutManager called usesDefaultHyphenation. And in the past, you'd be able to get the NSText classes to hyphenate it for you by using an NSParagraphStyle to control the threshold of hyphenation. This LayoutManager property is a little bit easier to use.

It defaults to off. In which case you got no hyphenation, like on the left. And if you set it on, we'll pick a default value for hyphenation. And you can see on the right that we've hyphenated encyclopedia and internationalization. So we think these Text API's will really help you polish the corners and edges around your text systems.

We have some great new stuff in NSToolbar. The First Edition is a new property on NSToolbarItem called isBordered. In the past, if you wanted to get this push-button style appearance in an NSToolbar, you would have to allocate your own NS -- or instance of NSButton and configure it and then you'd use it as a custom view on your Toolbar item. And that would work but it was extra effort for you, and additionally, you couldn't take advantage of NSToolbarItem's built-in support for automatic enabling and disabling.

But if you go ahead and use this as bordered property, you'll get all of that for free. Additionally, NSToolbarItem has a new title property which lets you configure your Toolbar items to be string-based buttons instead of iconic ones. And this is distinct from the label property. Which would appear below these buttons if we have configured the Toolbar to show labels as well.

That is not the NSToolbar-related class to gain functionality in macOS 10.15. We have also added a number of features to NSToolbarItemGroup to make it incredibly versatile and useful and the first of these is a number of convenience constructors for it. And these are just going to let you build the same great Toolbar UI's in fewer lines of code.

But NSToolbarItemGroup has become more flexible at the same time. If you look at the image on the right side of the screen. You can see that it now has support for representing its items as a segmented control. And it can also represent them as pulldown and pop-up menus too. So this makes it a very versatile Toolbar control. Because of the way it uses the other Toolbar items as a vocabulary. We can also automatically create a collapsed representation for when you have too many Toolbar items for the window width.

There's a very similar effect you can get using a new NSMenuToolbarItem class. And this is much like the menu item representations of the ToolbarItemGroup but it uses an NSMenu as currency instead. And that's significant because you can use NSMenu features like sub menus or separator items or even the ability to use a custom view for your menu items. So it's a very powerful tool, if you want to have sophisticated drill-down behaviors in your Toolbar. NSTouchBar has also received a few enhancements and macOS 10.15. The first of these I want to note is a new class property on NSTouchBar itself. And that's isAutomaticCustomizedTouchBar MenuItemEnabled.

And that will sound familiar. NSApplication has that exact same property. You could use this Touch Bar one in code where you wanted to factor it in such a way to not reference the NSApplication. And one example of that is if you're writing a UIKit application you're not going to have an NSApplication instance to talk to anyway.

A more significant control is the new NSStepperTouchBarItem class. Just like an on-screen stepper, this is very useful for when you're doing a discrete entry for things such as dates and numbers. But given the larger size in the Touch Bar and the horizontal layout, you can also use this for new applications. Like visually selecting the tool in a drawing app. So we're really excited about this new TouchBarItem class. We think you'll be able to put it to good use in your applications.

NSSliderTouchBarItem has a few small enhancements too. You may have experienced a case where you used an NSSliderTouchBarItem. And it was a little bit too small for your tastes. You could fix this by grabbing the slider from the TouchBarItem instance and adding auto layout constraints to it. In macOS 10.15, you can just set the minimum slider width directly on the item and we'll take care of that for you. Similarly, if your slider has global ambitions. You can check them by using the maximum slider with the property.

And lastly, we'll talk about a bit -- a little bit about Sidebar Metrics. In macOS 10.15, you can toggle the size of a Sidebar using the setting and the general pane of System Preferences. And we default to medium. But you can also use small and large. And I want to call this out because if you haven't known about this feature.

You maybe have not been including artwork appropriate for these small and large sizes. So if you're using bitmap artwork, go ahead and add representations for that. Or use a resolution independent version. Similarly, there's a new feature and macOS 10.15 to allow automatically picking the light and dark appearance. That's also available in the general pref pane.

Okay, we covered controls for Toolbars and Touch Bars. Let's talk about some controls that are more broadly applicable. The first of these, we're excited to announce, this is NSSwitch. NSSwitch is a full subclass of NSControl. It supports bindings. It supports formatters. But it exists alongside the existing checkbox functionality. A question you probably have in your mind is, "When should I use NSSwitch? And when should I use a checkbox?" And if you are already using a checkbox, you should probably keep using a checkbox. They are generally the right control to use.

We think NSSwitches are better used when you have a really heavy toggle. Something that's toggling a lot of functionality on and off. And in this example I have here, we have a master toggle on the left, which is going to enable all of the individual sharing services on the right.

In macOS 10.15, we've invested a lot of effort into NSCollectionView. And one of the things we're excited to talk about is compositional layout. And in this scheme, you no longer need to subclass NSCollectioViewLayout to modify it. There are a number of interesting features you can throw in. Such as container-relative sizing, layout breaks and sections. As well as nestable groups.

And also making individual sections scrollable. And of course, all of that works in both right-to-left and left-to-right languages. There is also a new CollectionView feature called Diffable Data Source. And these are identifier-based data sources that let us track things like the addition or removal of items or the movement of an item between two locations. And we can automatically infer the right animations to use. So this means you won't have to use performBatchUpdates or reloadData.

Okay, backing away from app-specific controls to an IB feature. IB storyboards are a really great way of connecting the various view controllers in your application. And historically, your view controller would be initialized through in it with coder. And you'd have to find a different way of getting different information into the view controller.

That wasn't necessarily difficult. But it did mean your code was factored maybe more broadly than you wanted. If you look at the snippet here, you can see I have a function called showPetDetails. And this returns a new view controller passing along a coder from IB. As well as inserting our own notion of a selected pet name.

So this is a great way of bundling those separate initialization and configuration steps. And the other important thing to note about this is there's this IBSegueAction annotation attached to this function. And by doing that, we can go to the connections inspector and interface builder for our segue and wire it up directly to this method. So we think this is very useful for adding extra configuration into your view controllers and storyboards.

So a great feature of all AppKit controls is how they support auto layout. They automatically know how to measure their content and feed that into the auto layout engine. And that means that you can do things like change the strings on these text fields and buttons. And auto layout will just automatically reflect the view hierarchy and window for us to look great.

Sometimes, though, there are UIs where that's actually not important. So in this grid view, it's the grid that is determining the size of everything else and the intrinsic size of these labels doesn't actually matter. But normally, AppKit would still go ahead and measure these controls and feed them into the auto layout engine even though they won't affect the final result.

In macOS 10.15, you can turn that off. NSView gains two new properties to turn off the measurement behaviors for both horizontal and vertical axes. And we think that can be a great way of getting back some performance in UIs where you know the intrinsic size of a control isn't going to matter.

There's one other controller-related thing I want to talk about. And it's a bit more broad than NSControl. That's NSResponder. And its behavior relating to block Capture. So if you look at our snippet on screen you can see we have two blocks. We have an outer block that's going to be executed on a background thread. And we have an inner block that's going to be executed on the main thread. And this is a fairly common pattern. We do our work in the background. And then we go ahead and assign the results of that work to the UI on the main thread.

But this snippet in macOS 10.14 could have led to crashes and corruption. And that's because if the only thing retaining this text field is these blocks, the order of destruction of the blocks isn't defined. If the outer block deallocates last, the text field will deallocate on a background thread. And the text field, by virtue of being a responder, is part of the responder chain.

It can be part of the view hierarchy or the key view loop. So there's all these global data structures that aren't safe to modify from the background which is what dealloc would do. In macOS 10.15, this isn't a problem. NSResponder will automatically move the dealloc method for it and its descendants to the main thread.

So it becomes safe to capture these in blocks without being concerned about where those blocks are released. And we think this is going to remove a whole complex set of crashes for many of your apps. Where the corruption from doing work on a background thread isn't visible until seconds or minutes afterward.

So I want to talk about Open and Save panels for a moment. We have a fairly broad change in macOS 10.15. And that's that Open and Save panels are now using a separate process. This is a behavior that's already been present for Sandbox applications and we've simply brought it over to the remaining apps.

Generally, this should be a silent change. We don't think you're going to notice anything here apart from some performance and security benefits. However, if you are sub-classing Open and Save panel and relying on specific view hierarchy configurations you might run into problems. And we'd be happy to see you in the labs to talk about those and help work through them.

We also have some new NSWorkspace methods in macOS 10.15. These are methods that can open one or more URLs or open an application. And that will sound familiar because you'll think NSWorkspace already has methods to do that. It does. But the new methods are asynchronous. So they're not going to block the main threat at all. When the application finishes launching or the operation is cancelled we will call you back using a completion handler. And in addition to being asynchronous. these methods also offer a high degree of control over how we launch those URLs and applications.

And that control is achieved through the new NSWorkspace.OpenConfiguration object. This is just a sampling of the knobs it has to play with. But you can control whether the user needs to participate in this process. So for example, if you're requesting a server mount or if we don't know what application to use, the user might need to pick which application.

And you can instead suppress that behavior and just cancel the Open process. You can also control whether an application or document is added to the Recents menu. And there's an entire variety of things for controlling which applications can be hidden on launch or which are activated in the background or foreground. So we think whatever your URL application opening needs, NSWorkspace will accommodate a wonderfully in macOS 10.15.

We're going to talk about Events for a little bit. And there's a feature I want to show you. And this is -- if you hover your mouse over the green button in the window title bar, you're going to get this new menu. And the first set of options concerns things like making a window full screen or positioning it in a shared full-screen space. And those are fairly useful.

But there's another feature that I think is even more useful and that's the ability to move a window to another display. As someone who is constantly moving their laptop to different external monitors, I found this to be incredibly useful. But you don't actually have to use a conventional display. iPads will function as additional displays now too.

So you kind of see where I'm going with this. Given that the iPad application is named Pencil Draw. And we have this beautiful cursive script on there. This supports Apple Pencil. So many iPads can now function as tablet devices for Macs. So in macOS 10.15, we're going to have many more tablet users. If you've been thinking about adding tablet support to your app at any point in the last many years, now is a great time to adopt it. So I'm going to show you what you need to know to do that.

Tablet Events come in basically as normal mouse events. There's a difference though. And that's if you pay attention to the NSEvent SubType field, there is a tabletPoint value there. And when you see a tabletPoint Event, it one, comes from a tablet, but it's also going to have pressure information attached. And paying attention to that pressure information is critical for making things like that nice cursive stroke.

Where you have different pen widths throughout it. If you've used the pencil APIs on iOS in the past, there was something you could do by registering a handler. To retroactively receive updates to pressure in the past. That is not present on the Mac. You can just pay attention to the pressure field in the NSEvent.

There's another convention related to the Apple Pencil I want to mention. And this is that you can double tap it, the side of the pencil, and it will switch whatever the current tool is in a drawing app, for example, and we call this the changeModeEvent. There's a new EventType forum on this event. And there's a new responder method to handle directing that through the responder chain.

In many cases, you might want to have tablet functionality that isn't actually anchored in a responder subclass like a View. But you might still want to handle events directly. And there's a way you can accomplish this. Using the existing LocalEventMonitor API. So if you look at the snippet on the bottom of the screen, you can see that we use the NSEvent.addLocalEventMonitor for events function to catch these changeModeEvents.

And then we just cycle through our tools and we return the event allowing it to flow through the rest of the responder chain. So that can be a great way of factoring your code more usefully. Okay. Let's talk about a Foundation feature. We have some new Geometry data types. I know normally, when we get into Foundation, everyone's on the edge of their seat. This year, you can pick which edge of the seat you're on.

[ Laughter ]

The data types are NSDirectionalRectEdge, NSDirectionalEdgeInsets, and NSRectAlignment. And instead of working in currency, like Min X or Max S, or left and right. these are using leading and trailing identifiers instead. So they'll automatically flip based on context in a left-to-right or right-to-left system. And NSCollectionView uses these exactly for this purpose. We think you'll be able to adopt them directly in your applications too.

Another Foundation feature I want to talk about that will help with localization is new formatters. The first of these is the NSRelativeDateFormatter. And NSRelativeDateFormatter has two important properties, a dateTimeStyle, which allows you to pick whether you're sort of working at absolute units or more colloquial terms. The one week ago versus last week. As well as the unitsStyle, controlling how verbose or how terse our language is.

There's also a new NSListFormatter class. And NSListFormatter is interesting in that instead of formatting sort of a scalar object, it will format an array of objects instead. And it will do that by using a separate item format for each object individually. The value of the List Formatter adds is in knowing where to place the commas between the individual formatted strings. As well as whether at Oxford comma is necessary or a conjunction. There is a session covering this in much greater detail later, which I encourage you to check out.

Foundation also has a new feature we're very excited about called Combine. And Combine is a Swift API for connecting properties of the objects in your applications to other properties in your application. So a specific example I want to show is this awakeFrontNib method we've implemented where we go ahead and we bind to the name property from our model object to the value of an NSText field.

And whenever that name changes, that text field is going to update its string. So this is incredibly powerful. It has applications beyond just UI binding. And there's another session dedicated to specifically this that we think is going to be fantastic. So go ahead and check that out this week, too.

And finally, I want to mention some changes in system extensions for macOS. We have a small addition to the system extension family in the form of a non-UI file provider action extension. And if you are familiar with a UI-based file or act -- file provider action extension, this is the same thing. But sometimes, you just don't need that extra UI. You can do without it. And this satisfies that need.

Something else that we think is even more interesting is there's functionality. That in the past, you would have had to use a Kernel Extension to add the DOS. And we've now made system extensions to do similar things. We have new Network Extensions. We have DriverKit to help writing certain types of device drivers.

And we have a new Endpoint Security system that will help write antivirus software. So if you have been writing kernel extensions all these years, we think these will be very useful for you. We're excited with the security enhancements we get to make around this. And we think you'll be excited about not doing kernel mode debugging anymore.

So that covers our additions. I want to remind you of many of the great things that we covered today. We had additions for NSColor including new dynamic system colors, new ways of embedding your own programmatic dynamicism into the NSColor system, as well as, a color sampler class you can use yourself for picking colors directly from the screen.

We covered a number of APIs in NSScreen including those for you to make great usage of Extended Dynamic Range. And we had an entire variety of text enhancements. If you want your apps to look great in dark mode and you're presenting either simple or Rich Text, the dark mode enhancements are going to be great. The text checking controllers will let you enrich your own text engines like never before.

And our compatibility between iOS and macOS regarding text sizing is very useful especially given the presence of UIKit on the Mac this year. We covered controls like NSSwitch, as well as CollectionView. And we definitely encourage you to check out the CollectionView session because CollectionView has become a very important part of our UI vocabulary.

We covered some great enhancements for NSToolbar allowing you to make push buttons more easily and more versatile ways of using the ToolbarItem group. And then we've also covered some things for handling tablet events in NSEvent and specific support for the Apple Pencil. And again, with so many more tablet users coming to the Mac in the near future we think if your app can use tablets, it's a great feature to add. And we wrapped up with the localization enhancements for NS -- or for Foundation geometry data types and the new formatters. So we hope you're excited to adopt these two. And please have a great week. Thank you very much.

[ Applause ]