Guides and Sample Code Developer
Document Generated: 2017-03-27 11:47:00 -0800
OS X Release Notes Copyright © 2016 Apple Inc. All Rights Reserved.

macOS 10.12 - 10.12.2 Release Notes
Cocoa Application Framework

The Cocoa Application Framework (also referred to as the Application Kit, or AppKit) is one of the core Cocoa frameworks. It provides functionality and associated APIs for applications, including objects for graphical user interfaces (GUIs), event-handling mechanisms, application services, and drawing and image composition facilities.

These are the combined AppKit release notes for all versions of 10.12.

Release notes for AppKit from 10.11 and earlier releases can be found here.

Note that even though some APIs and descriptions refer to the APIs in Objective-C, and some others in Swift, unless otherwise specified all AppKit APIs are available in both Objective-C and Swift.

Marking updated APIs in headers

New APIs in headers are marked with decorations that include references to "10_12_2":
 NS_AVAILABLE_MAC(10_12_2), NS_AVAILABLE(10_12_2, <iOS Release>), NS_CLASS_AVAILABLE(10_12_2, <iOS Release>), NS_ENUM_AVAILABLE(10_12_2)
Deprecated APIs are marked with:

NS_DEPRECATED_MAC(<Release when introduced>, 10_12_2) or NS_DEPRECATED_MAC(<Release when introduced>, 10_12_2, "Suggested alternative")

Runtime Version Check

There are several ways to check for new features provided by the Cocoa frameworks at runtime. One is to look for a given new class or method dynamically, and not use it if not there. Another is to use the global variable NSAppKitVersionNumber (or, in Foundation, NSFoundationVersionNumber):
double NSAppKitVersionNumber;
. . .
#define NSAppKitVersionNumber10_7 1138
#define NSAppKitVersionNumber10_8 1187
#define NSAppKitVersionNumber10_9 1265
#define NSAppKitVersionNumber10_10 1343
#define NSAppKitVersionNumber10_10_2 1344
#define NSAppKitVersionNumber10_10_3 1347
#define NSAppKitVersionNumber10_10_4 1348
#define NSAppKitVersionNumber10_10_5 1348
#define NSAppKitVersionNumber10_10_Max 1349
#define NSAppKitVersionNumber10_11 1404
#define NSAppKitVersionNumber10_12 1504
#define NSAppKitVersionNumber10_12_1 1504.60
One typical use of this is to floor() the value, and check against the values provided in NSApplication.h. For instance:
if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_9) {
/* On a 10.9.x or earlier system */
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_10) {
/* On a 10.10 system */
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_10_x) {
/* on a 10.10.x system */
. . .
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_11) {
/* on a 10.11 or 10.11.x system */
} else {
/* on a 10.12 or later system */
Note that unlike most AppKit software updates, 10_10 software updates incremented the AppKit major version, which accounts for the specific advice for 10_10.x. Other special cases or situations for version checking are discussed in the release notes as appropriate. For instance some individual headers may also declare the versions numbers for NSAppKitVersionNumber where some bug fix or functionality is available in a given update, for example:
#define NSAppKitVersionWithSuchAndSuchBadBugFix 1138.42

Backward Compatibility

One backward compatibility mechanism that is occasionally used in the frameworks is to check for the version of the system an application was built against, and if an older system, modify the behavior to be more compatible. This is done in cases where bad incompatibility problems are predicted or discovered; and most of these are listed below in these notes.

Typically we detect where an application was built by looking at the version of the System, Cocoa, AppKit, or Foundation frameworks the application was linked against. Thus, as a result of relinking your application against the latest SDK, you might notice different behaviors, some of which might cause incompatibilities. In these cases because the application is being rebuilt, we expect you to address these issues at the same time as well. For this reason, if you are doing a small incremental update of your application to address a few bugs, it's usually best to continue building on the same build environment and libraries used originally.

In some cases, we provide defaults (preferences) settings which can be used to get the old or new behavior, independent of what system an application was built against. Often these preferences are provided for debugging purposes only; in some cases the preferences can be used to globally modify the behavior of an application by registering the values (do it somewhere very early, with -[NSUserDefaults registerDefaults:]).

macOS 10.12.2 Release Notes

Support for NSTouchBar

We introduced a version of macOS 10.12.1 with API to support the Touch Bar. There was also a version of macOS 10.12.1 that did not include support for the Touch Bar. In order to simplify the API story going forward, we have marked all NSTouchBar related API as available on 10.12.2 and later.

Please see the documentation for detailed information on how to use these classes, and see notes below for additional guidance and known issues.

Support for replacing the escape key in NSTouchBar

In MacOS 10.12.2 the NSTouchBar class has a new property – escapeKeyReplacementItemIdentifier. When non-nil the item with the specified identifier replaces the normal system provided escape key. This item should be provided by the delegate in the touchBar:makeItemForIdentifier: method, or located inside the NSTouchBar's templateItems set. For consistency with the rest of the system, the item should generally be a button, and should be used for canceling operations, or operations that can be undone.

Buttons in the esc key region will be automatically sized to the standard esc key width, and will only grow wider if their content requires it. In order to allow as much content as possible, they have modified metrics to reduce their inner padding. However, you should consider the space limitation when choosing localized strings in order to allow the button to stay at the standard width.

The escapeKeyReplacementItemIdentifier should be unique and not present in the normal defaultItemIdentifiers array.

If multiple NSTouchBar instances have escape key replacement items, the NSTouchBar provided closest to the first responder wins. Only NSTouchBar instances provided by NSResponders will be searched for escape key replacement items.

NSSliders in NSPopoverTouchBarItems

NSPopoverTouchBarItems that support press-and-hold and contain NSSliderTouchBarItems now have a one second delay before being dismissed after a press-and-hold gesture finishes. During that one second, interaction with the slider can be resumed and further delay the automatic dismissal of the popover.

Control appearance during NSTouchBar customization

Customization will now show the stateless appearance of NSTouchBarItem controls in both the on screen palette and the bar preview. This means that controls will not show their disabled, highlighted, or selection state while the bar is being customized.

NSCollectionViewFlowLayout fix

macOS 10.12 introduced an unintentional change in the way items are aligned in an incomplete (non-full) solitary row.  macOS 10.12.2 restores the alignment behavior from previous releases, where items in a single row are positioned the same as in the last row of a multi-row flow layout.

NSInspectorBar fix

32-bit apps running on 10.12.0 and 10.12.1 would crash after enabling NSTextView’s formatting bar (by setting `usesInspectorBar` to YES). This is fixed with 10.12.2.

macOS 10.12.1 Release Notes

Context Transition Animations in the Touch Bar

AppKit will animate changes to which NSTouchBarItems are presented to the user any time a change is made to an NSTouchBar or the responder chain changes.

In order to avoid unnecessary animation, AppKit will notice when items have the same identifier and frame and will not animate those changes. In order to achieve this result, use the same itemIdentifier between NSTouchBarItem instances that represent the same object to the user in different instances of NSTouchBar. If the responder chain changes such that NSTouchBar 'A' is being replaced by NSTouchBar 'B' and they both include a button with the title 'Cancel' the same itemIdentifier should be used for both items. AppKit will notice NSTouchBarItem instances that have the same itemIdentifier and the same frame and will not animate them even though the instances are changing.

It is important to note, however, that if the frame of the item being added is different from the frame of the item being removed, AppKit will still animate the change even if the itemIdentifiers are the same. If possible, avoid changes that would cause the frame of these items to change in between presentations.

NSTouchBar Support in Alerts

NSAlerts will automatically mirror buttons into the Touch Bar. The buttons presented in the bar will call -performClick: on the corresponding buttons in the NSAlert when tapped.

Custom windows presented as sheets or as modal windows to the user will need to add this behavior manually as AppKit will not automatically add these buttons to the bar.

Principal Items in NSTouchBar

The principal item of an NSTouchBar will try to occupy the same amount of space as the QuickType item. If a principal NSTouchBarItem can not occupy the width of QuickType, it will be sized as close to that width as possible.

Minimum and Maximum Size of NSTouchBarItems

AppKit will measure the minimum and maximum sizes of NSTouchBarItems at runtime. AppKit will cache these measured values and recalculate when necessary. Both the minimum and maximum sizes are measured at a priority of 200.

An NSTouchBarItem's view should use auto-layout when possible to express the sizes which the view is capable of occupying. Use constraints with priorities higher than 200 to express minimum and maximum thresholds. AppKit will notice if a constraint is changed and recalculate the minimum and maximum widths of the view.

When using intrinsicContentSize, call -invalidateIntrinsicContentSize when something changes that affects the intrinsicContentSize. Otherwise, AppKit will not notice the change and will not measure the new minimum and maximum sizes of the NSTouchBarItem's view.

In general, NSTouchBarItem's views should not have an opinion about their width outside of their minimum and maximum sizes. AppKit will decide how much space a given view should occupy within the minimum and maximum size of a view relative to what else is in the Touch Bar.

NSTouchBar and Right to Left support

NSTouchBar does not currently support right to left specific behaviors at the top level. This means that AppKit will not automatically flip NSTouchBarItems in a right to left localization.
Please do not manually reorder defaultItemIdentifiers as this will break user customized bars. Instead, try to encapsulate views that absolutely must flip inside of single views such as an NSStackView. NSView subclasses will continue to flip in right to left localizations when using auto-layout based on the NSUserInterfaceLayoutDirection. In general, anything beyond encapsulating views inside of a single NSView should be avoided as AppKit support may change in the future.

Segmented Control minimum size

Beginning with macOS 10.12.1, NSSegmentedControls will allow their titles to be easily compressed if they also have images.  In this case, the default compression resistance drops to 100, and a "minimum size" constraint is applied with a priority of 750 to prevent clipping of the images or bezel.  If you want your segmented control to be harder to compress, it will be necessary to set a compression resistance priority larger than this default.

Touch Events and Event Routing

The Touch Bar produces direct touch events that contain a set of NSTouches. These events are similar to the indirect touch events that are produced by Magic Trackpads, but there are some differences you should be aware of. For example, direct touch events are routed much like on iOS. Each Direct touch is routed to its hit tested view and may also be sent to gesture recognizers. See the section on NSTouch for more details.

Like indirect touches, each direct touch event and resulting NSTouch is an immutable snapshot of the event or touch at that instant. This is different from iOS where the same UITouch instance is reused for the duration of that touch.

Direct touch events are noted by the new event type, NSEventTypeDirectTouch. While there is a corresponding NSEventMaskDirectTouch, you cannot acquire direct touch events via -nextEventMatchingMask: or similar tracking methods. Direct Touches don’t flow through -sendEvent: either. Instead, direct touch events are routed upon receipt by the application. Important Note: This means that direct touch events are routed even when your app is in a tracking loop.

Direct touch events are coalesced. That is, all direct touch events in the event queue since the last touch event delivery are combined into a single event. The following function allows you to get the individual touches that make up the coalesced touch when needed.
  /* An array of auxiliary NSTouch’s for the touch events that did not get delivered for a given main touch.
This also includes an auxiliary version of the main touch itself. Only valid for NSEventTypeDirectTouch events.*/
public func coalescedTouches(for touch: NSTouch) -> [NSTouch]
NSView has been updated for direct touches as well. Notably, the acceptsTouchEvents property has been deprecated in favor of the new allowedTouchTypes property. The allowed touch types can be either empty, .indirect, .direct or both. For pre-10.12 built application, the default is empty. For applications built on 10.12 or later, the default is .direct. Your custom view can receive touch events by overriding the following responder functions:
  public func touchesBegan(with event: NSEvent)
public func touchesMoved(with event: NSEvent)
public func touchesEnded(with event: NSEvent)
public func touchesCancelled(with event: NSEvent)


Direct touches are exposed as the NSTouch object. New properties and functions have been added to handle the differences between a direct touch from the Touch Bar and and indirect touch from a trackpad. You can ask the touch for its type so you know which functions are available to you.
  public enum NSTouchType : Int {
case direct // A direct touch from a finger (on a screen)
case indirect // An indirect touch (not a screen)
  public var type: NSTouchType { get }
Direct touches do not have a normalizedPosition in the digitizer space. Instead their position is in view coordinates.
  public func location(in view: NSView?) -> NSPoint
public func previousLocation(in view: NSView?) -> NSPoint
AppKit will throw an exception if you attempt to acquire the wrong type of position for the type of touch.

As NSTouch objects are immutable, use the .identity property to track a specific touch throughout its life. Use the isEqual function to compare two touch identities.

Currently, the vertical position of all touches on the Touch Bar is generated from approximately the vertical center of the digitizer. As such, there is no vertical movement in touches in the current incarnation.


Direct touch support has been added to most AppKit gesture recognizers. The complete list is: NSClickGestureRecognizer, NSPressGestureRecognizer, NSPanGestureRecognizer and NSMagnificationGestureRecognizer. By default, gesture recognizers do not receive touches. You can enable this by setting the new allowedTouchTypes property to .direct. Note: at this time, gesture recognizers still do not receive indirect touches. In addition, with the exception of NSMagnificationGestureRecognizer, you must set the numberOfTouchesRequired to a non zero value.

NSGesture recognizer subclassers can receive touch events by overriding the following responder functions:
  public func touchesBegan(with event: NSEvent)
public func touchesMoved(with event: NSEvent)
public func touchesEnded(with event: NSEvent)
public func touchesCancelled(with event: NSEvent)
Direct touches do not send shouldAttemptToRecognizeWithEvent messages to their NSGestureRecognizerDelegate. Instead the iOS approach is used where the delegate is sent a message for each touch.
  optional public func gestureRecognizer(_ gestureRecognizer: NSGestureRecognizer, shouldReceive touch: NSTouch) -> Bool


macOS 10.12.1 introduces NSScrubber, a new AppKit control which arranges a finite collection of selectable content within the Touch Bar. It offers a variety of interaction modes and a flexible layout system. See the documentation for NSScrubber, NSScrubberLayout, and NSScrubberItemView for detailed information on how to build a scrubber control.

In 10.12.1, there is a known issue which prevents a NSScrubber configured for free scrolling and continuous selection from working properly with a layout that is dependent on the selected item.

Sharing Service Picker for NSTouchBar

NSSharingServicePickerTouchBarItem allows one to easily add a popover bar that utilizes the sharing service. It works similar to the NSSharingServicePicker, and the delegate derives from NSSharingServicePickerDelegate and adds the ability to dynamically provide the items to share.

NSSharingServicePickerTouchBarItem can not have the delegate be set to itself; this will cause an infinite loop.

Popover chevrons

The popover chevron is automatically displayed when the popoverTouchBar and pressAndHoldTouchBar properties refer to the same NSTouchBar instance. When the bars are different (including when the pressAndHoldTouchBar is nil) the chevron will not be displayed. Please note also that the chevron can not be automatically displayed when the item’s collapsedRepresentation has been replaced.

Popover nesting

Popovers are not nestable. Behavior is undefined if a popover item is used inside another popover item’s popoverTouchBar or pressAndHoldTouchBar.

A note on first responders

As the set of displayable bars is built from the responder chain, it is important that your responder chain matches what you expect. A common hiccup for views and view controllers is that they or a previous responder needs to be the first responder of a window. This might require over-riding the -acceptsFirstResponder method in a responder subclass.

NSTouchBar and Text

The NSTouchBar feature surrounding the text editing functionalities is a core part of the user experience offered by the new hardware. NSTextView participates in the NSTouchBar facility out of the box and provides text editing and formatting functionalities transparently without requiring adoptions from applications. NSCandidateListTouchBarItem, a concrete NSTouchBarItem subclass, can be easily configured to show the natural language candidate list appropriate for the current user document by working with NSSpellChecker and the text input system. NSTouchBar supports a text-related item identifier, NSTouchBarItemIdentifierCharacterPicker, and returns an NSPopoverTouchBarItem configured to show the system character picker from -itemForIdentifier:.

NSTextView Support

NSTextView should be able to present its NSTouchBar items out of the box without relying on any external controller from applications. For that, the view object implements -makeTouchBar configuring the item identifiers based on its property settings such as -isRichText. Also, NSTextView conforms to the NSTouchBarDelegate protocol and makes itself the delegate inside -makeTouchBar. This ensures its built-in items are properly associated with the bar through -touchBar:makeItemForIdentifier:. The method recognizes item identifiers for text color, text style (B/I/U), text alignment, text list, candidate list, and a group item preconfigured to contain the items above. The identifiers are NSTouchBarItemIdentifierTextColorPicker, NSTouchBarItemIdentifierTextStyle, NSTouchBarItemIdentifierTextAlignment, NSTouchBarItemIdentifierTextList, NSTouchBarItemIdentifierCandidateList, and NSTouchBarItemIdentifierTextFormat.

There are new APIs for controlling the items displayed by NSTextView. A new property, -allowsCharacterPickerTouchBarItem, controls whether to include the system character picker with the text view. The property is also available for NSTextField and its subclasses. When properties affecting the item identifiers such as -isRichText, -updateTouchBarItemIdentifiers gets messaged. NSTextViewDelegate can get notified via -textView:shouldUpdateTouchBarItemIdentifiers:.

Whenever the states for text NSTouchBar items need updating, -[NSTextView updateTextTouchBarItems] gets messaged.

NSSpellChecker Support for NSTouchBar Candidate Generation

NSCandidateListTouchBarItem is a special purpose NSTouchBarItem subclass that provides the candidate list functionality. It is used by default by NSTextView to show a natural language candidate list appropriate for the current user document by working with NSSpellChecker and the text input system. Other non-NSTextView clients may need their own access to candidate generation to obtain the same sort of candidates for use with NSCandidateListTouchBarItem, and NSSpellChecker provides facilities for that.

Candidate Generation

NSCandidateListTouchBarItem can be easily configured to work with NSSpellChecker and the text input system to display the candidate list appropriate for the user document content. Also, it can be configured to show arbitrary custom contents for applications. With the default configuration, the item is associated with NSTouchBarItemIdentifierCandidateList.

Showing candidates from NSSpellChecker
    The system candidate list based on the current selection inside the user document can be queried via the asynchronous method -[NSSpellChecker requestCandidatesForSelectedRange:inString:types:options:inSpellDocumentWithTag:completionHandler:]. The client passes in a string that should contain at least a paragraph’s worth of context around the point of interest (typically the insertion point). The selectedRange argument gives an indication of where the completion is occurring, and it should represent the portion of the string being checked that is selected, or be NSMakeRange(insertionPointIndex, 0) if there is an insertion point within or adjacent to the string being checked, or be NSMakeRange(NSNotFound, 0) if the selection is entirely outside of the string being checked.
    As with other NSSpellChecker asynchronous methods, the return value from this method is a sequence number that can be compared against the number passed to the completion block, for example to protect against the possibility of the text having changed in the interim. When the candidates become available, the completion block is called with an array of NSTextCheckingResult objects, specifying the range to be replaced, the replacement string, and the type of replacement. This call may be made on an arbitrary queue, so if clients need to operate on the candidates on the main queue they will need to arrange to send them there.

Showing candidates from the text input system
    The candidates from the text input system can be automatically displayed by configuring the candidate list item properly. The allowsTextInputContextCandidates property should be YES, and the client property should point to the target view conforming to the TextInputClient protocol. The view should return the candidate list item from -candidateListTouchBarItem.

Showing custom candidates
    With -setCandidates:forSelectedRange:inString:, applications can show arbitrary candidate such as contacts, e-mail addresses, telephone numbers, etc. With the configuration, the delegate property should contain an object conforming to NSCandidateListTouchBarItemDelegate for handling the touch on the Touch Bar.

NSTextView Candidate List Support

NSTextView supports NSCandidateListTouchBarItem and can manage the candidate list displaying the candidates from NSSpellChecker and the text input system. Also, NSTextViewDelegate now has additional methods for managing the candidate list item contents.

The automaticTextCompletionEnabled property controls whether to include the candidate list item in its NSTouchBar. NSTextField also has the corresponding property for controlling the behavior.

Two NSTextViewDelegate methods: -textView:candidatesForSelectedRange: and -textView:shouldSelectCandidateAtIndex:, can be used for managing custom candidates for the text view.

Related Methods

There is also an NSSpellChecker method, -deletesAutospaceBetweenString:andString:language:, for clients to use to after a candidate has been accepted, to determine whether or not to delete the trailing space after a candidate when the user subsequently types certain punctuation (such as periods and commas).

In addition, there is an NSSpellChecker method, +isAutomaticTextCompletionEnabled, to allow clients to find out the state of the user’s global preference for showing or not showing candidates, and a notification when this preference changes, NSSpellCheckerDidChangeAutomaticTextCompletionNotification.

Finally, one of the new keys introduced in 10.12 for clients to use with existing NSSpellChecker text checking methods, NSTextCheckingSelectedRangeKey, is needed in order to maintain consistency of results between these methods and the new candidate generation method. Clients should use this key in the options dictionary whenever they are calling NSSpellChecker methods like requestCheckingOfString:... or checkString:... that take an options dictionary. The value should be an NSValue created using -valueWithRange:, where the range should follow the same rules as the range passed in to requestCandidatesForSelectedRange:... Notice that the candidate generation method now has access to the selected range, so for consistency the text checking methods need access to it as well.

RTF Background Color Handling

In 10.12, 10.12.1, iOS 10, and 10.1, when a background color is set on a range of characters (using NSBackgroundColorAttributeName), and the resulting attributed string is saved as RTF and loaded back in, the characters following the range appear with a white background color, rather than no background color.  This is often not visible in cases where text is drawn on a white surface, but could be a problem otherwise.

This problem will be addressed in an upcoming release.

macOS 10.12 Release Notes

Some of the major topics covered in this document:

Overall API Updates

This release brings many API refinements, taking advantage of new API features in Objective-C and enabling APIs to come across more naturally in Swift.

Some of the key API update areas include:
- Adoption of Swift 3 API design guidelines, which has a large impact on the APIs as they appear in Swift.
- Adoption of Foundation Value Types, where appropriate in APIs. For instance NSData and NSURL in API now appear as Data and URL in Swift.  (Note that prefix dropping is a Foundation-only change and does not apply to other frameworks.)
- Updated names of enumerations to improve consistency and exposure in Swift.

NSCollectionView: Collapsable Sections

Finder’s icon view offers users the ability to collapse any section (each grouping by kind in “Arrange by: Kind” mode, for example) into a single horizontally scrollable row, via a “Show Less” button in the section’s header. A section will sometimes start out in this collapsed state, with the button (now titled “Show All”) toggling the section back into a normal flow layout. You can now easily offer the same capability to users of your NSCollectionViews.

To enable this feature:

1. Make your header view conform to the new NSCollectionViewSectionHeaderView protocol. This protocol provides an optional "sectionCollapseButton” property that we’ll use the help the CollectionView find the button.

2. Add an NSButton as a subview or descendant of your section header view. (If you’re using .xib files, you can do this in the interface editor.)

3. Set the button’s image or title to something general that indicates a toggle action — or, if desired, to indicate an initially uncollapsed state. (e.g. You’re likely to want it to read “Show Less”, or similar.)

4. Set up Auto Layout constraints to position your button as desired within the header view.

5. Wire the header view’s “sectionCollapseButton” outlet to your button.

6. Wire your button’s action to send -toggleSectionCollapse: to the First Responder. (Alternatively, you can use another action of your own, and have its implementation use either -toggleSectionCollapse: or the programmatic collapse/expand API described below to change the section’s state as desired.)

When the user clicks the button, -toggleSectionCollapse: should get routed to the NSCollectionView, which identifies the section based on the enclosing header view instance, and toggles the section’s collapsed state.

As in Finder’s icon view, the button is automatically shown when applicable, and hidden when not. If you want to change the title of the button to reflect the current collapsed/uncollapsed state, you can do so by overriding the -toggleSectionCollapse: action method on NSCollectionView to update the button’s title, after calling up to super. For example:
// Override -toggleSectionCollapse: to update the button's title.
- (void)toggleSectionCollapse:(id)sender { // "sender" is the "Show Less" / "Show All" button.
    // Let NSCollectionView collapse or expand the corresponding section.
[super toggleSectionCollapse:sender];
    // Update the button's label to show the action it will now perform.
if ([sender isKindOfClass:[NSButton class]]) {
// We must have a Flow layout, to be able to collapse and expand sections.
NSCollectionViewFlowLayout *layout = (NSCollectionViewFlowLayout *)[self collectionViewLayout];
if ([layout isKindOfClass:[NSCollectionViewFlowLayout class]]) {
            /* Find the containing header view, and from it the corresponding sectionIndex.
(The `sender` button is required to reside in a section Header view.) */
NSSet<NSIndexPath *> *headerIndexPaths = [self indexPathsForVisibleSupplementaryElementsOfKind:NSCollectionElementKindSectionHeader];
NSUInteger sectionIndex = NSNotFound;
for (NSIndexPath *headerIndexPath in headerIndexPaths) {
NSView *headerView = [self supplementaryViewForElementKind:NSCollectionElementKindSectionHeader atIndexPath:headerIndexPath];
if (headerView && [(NSView *)sender isDescendantOf:headerView]) {
sectionIndex = [headerIndexPath section];
            if (sectionIndex != NSNotFound) {
NSString *newLabel;
if ([layout sectionAtIndexIsCollapsed:sectionIndex]) {
newLabel = [NSString stringWithFormat:@"Show All (%lu)", (unsigned long)[self numberOfItemsInSection:sectionIndex]];
} else {
newLabel = @"Show Less";
[(NSButton *)sender setTitle:newLabel];
This example method uses API that enables you to programmatically query and change the collapsed/expanded state of any section:
@interface NSCollectionViewFlowLayout
/* Returns YES if the specified section is currently collapsed; NO if not, or if there is no such section. Defaults to NO.
- (BOOL)sectionAtIndexIsCollapsed:(NSUInteger)sectionIndex NS_AVAILABLE_MAC(10_12);
/* Collapses the specified section to a single row, if it is not already collapsed.
- (void)collapseSectionAtIndex:(NSUInteger)sectionIndex NS_AVAILABLE_MAC(10_12);
/* Un-collapses the specified section, if it is currently collapsed.
- (void)expandSectionAtIndex:(NSUInteger)sectionIndex NS_AVAILABLE_MAC(10_12);

NSCollectionView: Floating Headers

Header and Footer views in a Flow layout can now be “floated”, using the same API provided by iOS’ UICollectionView.

Set these properties to YES to get headers that pin to the top of the visible area and footers that pin to the bottom while scrolling. These properties are archived with the layout's other persistent properties. Enabling this feature may affect the parenting of header and footer views.

@interface NSCollectionViewFlowLayout
@property BOOL sectionHeadersPinToVisibleBounds NS_AVAILABLE_MAC(10_12);
@property BOOL sectionFootersPinToVisibleBounds NS_AVAILABLE_MAC(10_12);
When sectionHeadersPinToVisibleBounds is set to YES, the header view (if any) for the topmost visible section will stay pinned to the top of the scroll area in preference to being scrolled out of view. As the user scrolls down, the header stays pinned there until the next section’s header (or the top of the next section, if the next section has no header) pushes it out of the way.

The sectionFootersPinToVisibleBounds property behaves similarly, with pinning to the bottom of the scroll area provided instead.

NSCollectionView: Scrollable Background View

An NSCollectionView’s backgroundView can now be set to scroll together with the CollectionView’s content, instead of floating stationary behind the content. When backgroundViewScrollsWithContent is YES, the CollectionView's backgroundView (if any) will match the CollectionView's frame and scroll with the CollectionView's items and other content. When NO (the default, compatible with the behavior on OS X 10.11), the backgroundView is made to fill the CollectionView's visible area, and remains stationary when the CollectionView's content is scrolled. This property is archived with the CollectionView's other persistent properties.

@interface NSCollectionView
@property BOOL backgroundViewScrollsWithContent NS_AVAILABLE_MAC(10_12);
Setting this property necessarily changes the way the backgroundView is parented. To float the backgroundView behind scrolling content, we make it a sibling of the CollectionView’s ClipView (as on 10.11). To have it scroll with the CollectionView’s content, we instead make the backgroundView a subview of the CollectionView.

The backgroundView property is meant to interoperate with backgroundColors (and now does so better, thanks to a fix in 10.12). If a CollectionView has both a backgroundView and backgroundColors, backgroundColors[0] will show through any areas not opaquely covered by the backgroundView. (backgroundColors beyond the first element are a legacy feature of NSCollectionView from OS X < 10.11. When using 10.11’s “new” NSCollectionView, only the first color is used.)

The backgroundView’s frame is set to match the CollectionView’s, and updated automatically to maintain that equality.

NSCollectionView: File Promise Drag Fix

On OS X 10.11, a dataSource-based NSCollectionView acting as the dragging source for a file promise drag would erroneously attempt to invoke the old -collectionView:namesOfPromisedFilesDroppedAtDestination:forDraggedItemsAtIndexes: delegate API method, instead of first checking for the newer -collectionView:namesOfPromisedFilesDroppedAtDestination:forDraggedItemsAtIndexPaths: API (and would raise an exception if the old-form delegate method wasn’t found). This has been fixed, so that NSCollectionView will first look for and attempt to invoke the new method. Failing presence of the new method, NSCollectionView will fall back to the old method, but only if it is a single-section CollectionView.

NSCollectionView: Delegate Message Send Fix

On 10.12, an NSCollectionView’s delegate now receives -collectionView:didEndDisplayingItem:forRepresentedObjectAtIndexPath: (and the corresponding items are placed in the CollectionView’s reuse queue) for all currently instantiated items when the CollectionView is removed from its window, and not just when the items are scrolled out of view or removed. This makes -collectionView:didEndDisplayingItem:forRepresentedObjectAtIndexPath: a more reliable cleanup opportunity for resources that may be associated with items. The same is true for -collectionView:didEndDisplayingSupplementaryView:forElementOfKind:atIndexPath: (which due to a bug was not sent at all on OS X 10.11).

On 10.12, -collectionView:willDisplaySupplementaryView:forElementKind:atIndexPath: is now sent for a supplementary or decoration view that is about to be displayed. Due to a bug, this delegate message was not sent on OS X 10.11.


NSCollectionViewGridLayout now implements -initWithCoder: and -encodeWithCoder: to persist and restore its properties as it should. It did not do so on OS X 10.11.


NSToolbar's contextual menu will no longer show the "Hide Toolbar" item in applications linked on or after 10.12. Please be sure to include a menu item in your application's menu bar to toggle this behavior.

NSTabView - New since WWDC seed

NSTabView now has two new enums used to determine its style. NSTabPosition describes the position of the tabs and NSTabViewBorderType describes the border of the tab view. This is now the preferred method over using NSTabViewType.

Setting the tabPosition or tabViewBorderType will affect the NSTabViewType. Setting the tabViewType will also set the tabPosition and tabViewBorderType.
TabViewBorderType of anything other than NSTabViewBorderTypeBezel will only be respected if NSTabPosition is NSTabPositionNone as all other configurations are invalid. In an invalid configuration (i.e. a tabPosition of NSTabPositionLeft and a tabViewBorderType of NSTabViewBorderTypeLine) the tabViewBorderType will default to NSTabViewBorderTypeBezel.

NSSlider isVertical

NSSlider and NSSliderCell's `vertical` property is now readwrite and has changed its type from NSInteger to BOOL. In previous releases, NSSliderCell would try to automatically determine its orientation based on the aspect ratio of a received cell frame. This also led to -1 being returned from `isVertical` if it could not make a determination (e.g. the cell frame had a zero size), and could lead to the slider changing orientation when it was resized.

With 10.12, the vertical property is set at initialization time based on the aspect ratio of the frame parameter, and defaults to horizontal in ambiguous (equal width/height) cases; however it is recommended to explicitly set the vertical property or use the convenience constructors. To dynamically change the orientation of the slider, explicitly set the `vertical` property.

NSSplitView Delegate

For apps linked against the 10.12 SDK, NSSplitView's delegate property has zeroing `weak` memory semantics, compared to the previous `assign` memory semantics. However, if the object being set as the delegate doesn't support weak references, it will fallback to having assign semantics.

When linked against an older SDK, the delegate will continue to have `assign` semantics even when run on 10.12 or later.

It is important for apps that deploy to older OS X versions to still code against the `assign` semantics, and clear the delegate property when the delegate object is deallocated.

NSAlert Delegate

For apps linked against the 10.12 SDK, NSAlert's delegate property has zeroing `weak` memory semantics, compared to the previous `retain` memory semantics. However, if the object being set as the delegate doesn't support weak references, it will fallback to having assign semantics on 10.12.

When linked against an older SDK, the delegate will continue to have `retain` semantics even when run on 10.12 or later.

It is important for apps that deploy to older OS X versions to still consider the `retain` behavior and protect against retain cycles.

NSAlert Used Outside of Runloop

With 10.11 showing a modal NSAlert (or any other UI) outside of the main runloop will cause it to not disappear on modal session end. With 10.12, these alerts will be visually dismissed for apps linked against the 10.10 SDK or earlier. For newer apps, alerts should only be shown within the main run loop; or in cases where that is not possible, apps should make sure to flush the CATransaction after the modal run of the alert finishes (i.e. +[CATransaction flush]).


Prior to OS 10.12, -[NSCursor initWithImage:foregroundColorHint:backgroundColorHint:hotSpot:] would act as a designated initializer. The color hint parameters were unused and are now deprecated. For apps linked on or after OS 10.12, the color hint initializer calls into the new designated initializer, "-[NSCursor initWithImage:hotSpot:]". Apps which depend on which initializer is called should move to the new designated initializer.

NSCursor now better handles NSImage objects that contain vector representations and/or bitmap representations larger than @2x. It will now use the best available representation when the cursor is scaled via Accessibility preferences.

Layout Pass

In 10.12, the deferred view layout pass has been cleaned up, optimized and extended. This has resulted in several changes that developers should be mindful of when implementing view layout.

The deferred view layout pass represented by [NSView setNeedsLayout:] and [NSView layout] is now independent of autolayout and constraints. As a result, you can now implement custom layout mechanisms by overriding [NSView layout] without implicitly activating autolayout on the window. For example, if a view has child CALayers, it can now cleanly lay out those child layers in a [NSView layout] override and simply call [self setNeedsLayout:YES] whenever the child layout geometry needs to be updated in a deferred layout pass.

Previously, there were times where CoreAnimation would trigger [NSView layout] calls on parts of the view hierarchy out of band with the rest of the layout pass, resulting in inconsistent layout pass behavior or sometimes excessive layout calls on parts of the view hierarchy. The view layout pass is now driven entirely by AppKit. There could be cases where custom views were laying out child views or layers in a [view layout] override and were not setting view.needsLayout=YES appropriately, but the problem was masked by CoreAnimation. The solution in these cases is to ensure that view.needsLayout=YES is set whenever necessary. Note that layout for a view is now automatically invalidated when the view’s frame size changes, so view.needsLayout=YES should only be necessary on relevant state changes.

When overriding [NSView layout], AppKit no longer requires calling [super layout]. In particular, the view.needsLayout bit is now cleared automatically outside of the [view layout] call. This allows you to completely override [view layout] and block all of the default layout behavior if so desired. Also note that the bit is cleared before [view layout] is called, which means that if you dirty layout during your [view layout] override (either via calling [view setNeedsLayout:YES] directly or by modifying constraints), it will schedule a second layout pass.

Coordinated with a generic layout pass, AppKit now attempts to be smarter about when to actually engage an autolayout engine on an NSWindow. Specifically, the presence of an override to [NSView updateConstraints] now indicates to AppKit that the view in question, by default, uses constraints, and as such will activate autolayout in any NSWindow into which it is placed. If, however, you are writing a custom view type that supports but does not require constraints, then the correct solution, as before, is to override the class-level [NSView requiresConstraintBasedLayout] method and return NO.

As part of the layout pass optimization, AppKit is now more strict about certain requirements and limitations of the API. In particular:

- Be mindful of how layout is applied in a deferred manner, such that a view cannot rely on the frames of any subviews being current when its frame changes or during the view’s layout call (the ordering is not guaranteed). If you implement custom layout behaviors on top of deferred constraint-based layout and require the frames being current, the correct method is to call [self layoutSubtreeIfNeeded], which will perform the layout pass synchronously for just that subtree. Also note that using [self layoutSubtreeIfNeeded] is in general good practice if you are relying on frames of descendant views provided by other frameworks or libraries, since it can be difficult to determine whether any of those components use deferred layout or not, and the answer might change from release to release.

- AppKit is now more efficient about only calling -layout on views when actually necessary, which can reveal holes where code previously did not properly invalidate layout when necessary (the above CoreAnimation case being one of those instances). If you find -layout method not being called when expected on your view, make sure that the view is actually marked as needsLayout=YES.

- There are certain API calls that are specific to autoresizing masks or constraint-based layouts, and using one or the other, particularly in view hierarchies where both methods are used, can lead to unexpected results. Specifically, the resizeSubviewsWithOldSize/resizeWithOldSuperviewSize pair of API calls are specifically tied to autoresizing masks and whether a view has autoresizesSubviews set, and as a consequence those API calls can—and most likely will—be called before any constraint-based view layout is performed. The best layout-method-agnostic method of watching for size changes on a custom view class continues to be overriding the [NSView setFrameSize] call, and the best method for laying out children is to override [NSView layout], since it no longer automatically implies autolayout activation.

- The constraint solver works best when a set of layout constraints are activated once and left alone to re-evaluate as necessary during resize. However, if you must modify constraints as your view resizes, the best method continues to be overriding [NSView updateConstraints] and then setting self.needsUpdateConstraints=YES from within an [NSView setFrameSize] override. This method reduces the chance of a layout loop, makes layout dependencies easier to debug, and allow AppKit to better optimize the performance of the layout changes.

Improved debugging support for layout

AppKit now provides some additional support for debugging layout feedback loops. If you encounter layout passes that do not terminate naturally, you can run your application with the following argument: -NSViewLayoutFeedbackLoopDebuggingThreshold 100. The framework will then track dirty layout and attempt to identify cycles, logging information that may be useful in isolating the problem.

To assist debugging redundant view layout, there are now two user defaults. NSViewLayoutStrictMode, when enabled, will log the pointer of the view receiving redundant layout. This behavior can be modified to throw an exception by setting the NSViewLayoutStrictModeThrowsException user default to YES. NSViewLayoutStrictModeThrowsException has no effect when NSViewLayoutStrictMode is not set to YES.

Item Based Dragging File Promises

The Drag & Drop API has been modernized with two new classes: NSFilePromiseProvider and NSFilePromiseReceiver. These new objects:
    •    Support drag flocking
    •    UTI based
    •    Pasteboard Writer/Reader compliant
    •    File coordinated when possible
Also, NSFilePromiseProvider is compatible with drag destinations using the non-item based drag file promise API. Likewise, NSFilePromiseProvider is compatible with dragging sources using the non-item based drag file promise API.

Dragging File Promise Source - Changed since WWDC seed

Use the NSFilePromiseProvider class when creating file promises. Instantiate one NSFilePromiseProvider for each file promised. Before writing any NSFilePromiseProvider to the pasteboard, it must contain a file type being promised and an NSFilePromiseProviderDelegate. The file type must be a UTI that ultimately conforms to kUTTypeData or kUTTypeDirectory. The NSFilePromiseProviderDelegate will do the heavy lifting of writing the promised file to the destination directory. Optionally, you may attach a userInfo object of your choosing to the NSFilePromiseProvider. This is often useful to determine which promise is being referenced when promising multiple files and using the same NSFilePromiseProviderDelegate instance.

There are only three NSFilePromiseProviderDelegate methods you need to implement:
- (NSString *)filePromiseProvider:(NSFilePromiseProvider*)filePromiseProvider fileNameForType:(NSString *)fileType;
Discussion: This method is called when the drag destination “calls in” the file promise. At this point you should determine and return the final filename, which should be the base filename, not a full path. Note: The drag process is halted while waiting for this method to return. Taking too long in this method may result in the drag getting cancelled. Do not start writing the file yet.

- (void)filePromiseProvider:(NSFilePromiseProvider*)filePromiseProvider writePromiseToURL:(NSURL *)url
completionHandler:(void (^)(NSError *errorOrNil))completionHandler;
Discussion: Write the contents of this promise item to the provided URL and call completionHandler when done. It is important to call the completion handler as the file writing is wrapped with NSFileCoordinator. Likewise, be sure write your file to the supplied url parameter. This method is called after the drag completes. Note: This request shall occur on the NSOperationQueue supplied by -promiseOperationQueue.
- (NSOperationQueue *)promiseOperationQueueForFilePromiseProvider:(NSFilePromiseProvider*)filePromiseProvider;
Discussion: Return the operation queue that the write request should be issued from. If this method is not implemented, the mainOperationQueue is used. While optional, it is strongly recommended that you provide an operation queue other than the main operation queue to avoid blocking your main thread.

Dragging File Promise Destination

Use the NSFilePromiseReceiver object to receive file promises. Since NSFilePromiseReceiver implements the NSPasteboardReader protocol, you get all the file promises on the drag pasteboard like so:
    NSArray<NSFilePromiseReceiver*> filePromises = [pasteboard readObjectsForClasses:@[[NSFilePromiseReceiver class]] options:nil];
Likewise you can enumerate the draggingItems by
   [draggingInfo enumerateDraggingItemsWithOptions:0 forView:view classes:@[[NSFilePromiseReceiver class]]
searchOptions:@{} usingBlock:^(NSDraggingItem *draggingItem, NSInteger idx, BOOL *stop) {
NSFilePromiseReceiver *filePromiseReceiver = dragItem.item
Compatibility note: A non-item based drag source (e.g. don’t use NSFilePromiseProvider) may promise multiple files on the same pasteboard item. To be compatible with these drag sources many NSFilePromiseReceiver methods return an array of values. Muti-file item based promises result in one NSFilePromiseReceiver per promised file.
+ (NSArray<NSString *> *)readableDraggedTypes;
Discussion: A view must register what types it accepts via -registerForDraggedTypes:. Use this class method to get the file promise drag types that NSFilePromiseReceiver can accept, in order to register a view to accept promised files. NSFilePromiseReceiver can accept file promises from both the item based NSFilePromiseProvider and the non-item based API. If you don’t register all these drag types you may fail to be notified about some file promise drags. Registration is simply: [view registerForDraggedTypes:[NSFilePromiseReceiver readableDraggedTypes]];
@property(copy, readonly) NSArray<NSString*> *fileTypes;
Discussion: Returns an array of UTIs for the filetypes promised. NSFilePromiseProvider promises 1 filetype per item. The count of fileTypes should tell you the number of promised files in this item, however, that is not guaranteed. Historically, some legacy file promisers only list each unique fileType once and write one or more files per type.
- (void)receivePromisedFilesAtDestination:(NSURL *)destinationDir options:(NSDictionary *)options
operationQueue:(NSOperationQueue *)operationQueue reader:(void(^)(NSURL *fileURL, NSError * __nullable errorOrNil))reader;
Discussion: This effectively calls in the promises. Therefore, only call once you are accepting the file promise. All file promisesReceiver's in a drag must specify the same destination location. The options dictionary is ignored for now. The reader block is called on the supplied operationQueue when the promised file is ready to be read. It is highly recommended that you specify an optation queue other than the main operation queue to avoid blocking the main thread waiting for the file promise to be written by the source (as this may be a long process). When the source is an NSFilePromiseProvider, the readerBlock call is wrapped in an NSFileCoordination read. Otherwise, a heuristic is used to determine when the promised file is ready to be read. Note: Writing of the promised file may fail. When that occurs, the readerBlock is still called with a non-nil error. There may be nothing at the fileURL, or it may be a partial / corrupt file.
@property(copy, readonly) NSArray<NSString*> *fileNames;
Discussion: Returns an array of the file names of the promised files that are being written to the destination location. This property returns an empty array until the file promise is called in via receivePromisedFilesAtDestination.


Built-in NSControl subclasses now automatically mirror some directional properties (e.g. NSButton’s imagePosition) when unarchived from a Base-localized Interface Builder archive into a right-to-left user interface. This behavior is suppressed if the control is configured with “Mirror” set to “Never”.

The cases of the NSControlSize enumeration have been renamed to have a common prefix, per modern naming conventions. The existing names are now deprecated.

The -[NSControl sendAction:to:] method incorrectly declared its `theAction` parameter as non-nullable. It is now correctly marked as nullable.


The previously-unused gradientType property, and corresponding NSGradientType enumeration, are now deprecated.


NSButton now has several new convenience constructors for creating system standard push buttons, checkboxes, and radio buttons:
NSButton’s keyEquivalentModifierMask property is now declared with type NSEventModifierMask instead of NSUInteger.


NSTextField now has several new convenience constructors for creating non-wrapping labels, wrapping labels, attributed labels, and editable text fields:
The -control:isValidObject: delegate method incorrectly declared the `object` parameters as nonnull. It is now correctly marked as nullable.


NSSegmentedControl has new convenience constructors for creating a segmented control given an array of labels or an array of images:


NSSlider has new convenience constructors for creating horizontal linear sliders:


NSImageView has a new convenience constructor for creating a non-editable image view with a given NSImage:

NSButton - New since WWDC seed

NSButton provides a new property, imageHugsTitle, which affects how the button image is positioned when the button is made larger than its intrinsic content size. By default, the image is always positioned relative to the bezel edge, but with imageHugsTitle = YES, the image is always positioned adjacent to the title text.

NSButton now exposes an imageScaling property, available back to 10.5 and later. Accessing this property is preferred over accessing the NSButtonCell equivalent.

NSPopUpButton - New since WWDC seed

For applications linked against the macOS Sierra SDK and later, NSPopUpButton no longer reserves drawing space for arrows if arrowPosition is set to NSPopUpNoArrow.

New Layout Container: NSGridView

NSGridView is an auto layout container for arranging content views into a grid. At a high level it's similar to NSStackView, except it allows for alignment across both rows and columns. Like a spreadsheet, rows and columns can all be varying sizes, or dynamically hidden & shown. Individual cells may be merged to achieve a layout that crosses the basic grid boundaries. See NSGridView.h for the API and more information.


NSLayoutConstraint now exposes properties for a firstAnchor and nullable secondAnchor. This is part of a longer-term move towards leveraging layout anchors more heavily in the API. Use of these is recommended over the existing item/attribute pairs, since some anchors cannot be represented that way. For this reason, NSLayoutConstraint's firstItem property is now nullable, and developers may begin to encounter valid constraints with nil items or NSLayoutAttributeNotAnAttribute.

NSViewNoInstrinsicMetric unavailable from Swift - New since WWDC seed

The NSViewNoInstrinsicMetric constant was replaced with the properly-spelled NSViewNoIntrinsicMetric in macOS 10.11, and is unavailable from swift. This can present a problem for swift developers that are using the 10.12 SDK, targeting macOS 10.10, and need to override intrinsicContentSize to not specify a size in one or both dimensions. In this case, it's acceptable to simply use -1.0 instead.


In NSAccessibilityConstants.h, we added the role constant “NSAccessibilityMenuBarItemRole” for items in the menubar.

In NSAccessibilityProtocols.h, the NSAccessibilityLayoutArea protocol now declares accessibilityFocusedUIElement as a read-only property rather than a method, so that it matches the NSAccessibility protocol. This allows Swift classes to implement the NSAccessibilityLayoutArea protocol by overriding the property.

In NSAccessibilityConstants.h, we added a new constant “NSAccessibilityRequiredAttribute” which indicates that a form field is required to have content for successful submission of the form. In NSAccessibilityProtocols.h, defined the corresponding protocol method for setting and getting the value of this attribute on an accessible object.


NSMenuItem’s keyEquivalentModifierMask property is now declared with type NSEventModifierMask instead of NSUInteger.

NSMenu and NSMenuItem now conform to the NSUserInterfaceItemIdentification protocol.

NSMenu and NSMenuItem now conform to the NSAccessibility and NSAccessibilityElement protocols. These classes now support the accessibility identifier and description that can be set in Interface Builder. You can also change the accessibility description in code with the -setAccessibilityLabel property setter.

NSMenu's delegate property is now declared "weak". The NSMenu implementation has actually stored a weak reference to the delegate (for zeroing-weak-compatible objects) since OS X v10.9, so this change is not a change in behavior but simply documents the current implementation.

Menus - New since WWDC seed

The popUpContextMenu and popUpMenuPositioningItem methods now align the menu at the popup location according to the user interface layout direction of the presenting view. If the view uses right-to-left layout, then the menu is right-aligned at the specified position; otherwise it is left-aligned.

NSTableView / NSOutlineView

NSTableView properly supports Right to Left Layout for applications that link on 10.12 and higher. Previously, the userInterfaceLayoutDirection was hardcoded to be NSUserInterfaceLayoutDirectionLeftToRight. NSTableView and NSOutlineView will now automatically flip the table column order for applications are right to left. This is only affects the visual representation of the table columns; the actual logical tableColumn array order is still maintained.

NSTableView (and NSOutlineView) now has a proper weak delegate and dataSource implementation. This means a developer is no longer required to clear them out to nil when the delegate (and/or dataSource) object is freed. This change applies to all applications on 10.12. Applications that target older releases should still reset the delegate to nil; doing so is harmless for 10.12 and higher. Note that the _delegate and _dataSource ivars in NSTableView have always been private, and should not be directly accessed. In 10.12, they are now opaque objects, and may not represent the real delegate or dataSource. Instead of directly using the ivars, one should use the property accessors.

NSOutlineView has a new property named stronglyReferencesItems to allow it to automatically retain the items returned to it when set to YES. The default value is YES for applications linked on 10.12 and higher, and NO otherwise. In general, this value should always be YES, but can be set back to NO for cases where the items would cause a retain cycle. This could happen if the item either directly or indirectly retained the outline view, which would cause it to never get released.

NSOutlineView will now reload the cell views associated with ‘item’ when [outlineView reloadItem:] is called. The method simply calls [outlineView reloadDataForRowIndexes:columnIndexes:] passing the particular row that is to be reloaded, and all the columns. For compatibility, this will only work for applications that link against the 10.12 SDK.

NSTableView will now reload "full width" cell views (meaning the column index for them is -1) when [tableView reloadDataForRowIndexes:columnIndexes:] is called, and the column index contains -1. For compatibility, this will only work for applications that link against the 10.12 SDK.

NSOutlineView - New since WWDC seed

NSOutlineView can now use isEqual: rather than pointer equality to compare items. NSOutlineView will use isEqual: rather than pointer equality if stronglyReferencesItems is set to YES.

Prior to 10.12, disabling mirroring in Interface Builder on an NSOutlineView would not work; this has been resolved. Applications that require an NSOutlineView to always be left-to-right (even in a right-to-left language) should explicitly set the userInterfaceLayoutDirection in code if they are targeting an OS prior to 10.12.


The class now has a new material for selection: NSVisualEffectMaterialSelection. In addition, a new property called emphasized can be used to indicate that the selection should draw in "first responder" status, or not.

NSWindow (new since GM)

In macOS 10.12, NSWindow will automatically flip the location of the standard window buttons (close/minimize/maximize buttons) to be on the right side of the window instead of the left when running in a right to left language. One can query this state by using the readonly NSWindow property windowTitlebarLayoutDirection. This may be necessary for applications that use titlebarAppearsTransparent and place controls underneath the titlebar aligned with the standard window buttons.


NSTitlebarAccessoryViewController supports NSLayoutAttributeLeading and NSLayoutAttributeTrailing to specify an abstract position that automatically flips depending on the localized language. These only work for applications that link on 10.12 and later. For applications that do not link on 10.12, NSLayoutAttributeLeft will automatically flip to the Right when in a Right To Left language and when run on 10.12.

NSWindow's backgroundColor would be ignored if a custom appearance was set on the window, and the window's contentView had wantsLayer=YES. This has been fixed for all applications.

Replacing the contentViewController on an visible NSWindow would leave the firstResponder set to the window; this has now been fixed to automatically determine the correct first responder when the contentViewController is changed. Applications targeting prior OS releases should explicitly assign the firstResponder in the new contentViewController's viewWillAppear.

NSWindow Automatic Window Tabbing

Automatic Window Tabbing allows any application to easily (and automatically) adopt tabs. This feature stacks multiple windows together and presents a tab bar in the window title bar area to make it appear to the user as though there is one single window. In reality, only the selected tab's window is shown, and all the other windows are hidden directly using CoreGraphics. An application only has to order a window in, and it will automatically be tabbed with similar windows based on heuristics the user's preference for tabbing. Ordering a window out removes the tab. Windows that are not visible are ordered out with respect to CoreGraphics, but are still considered visible with respect to AppKit / NSWindow.

There is a new user System Preference under the Dock section to control tabbing. The behavior of this preference is described in General Flow below.

The NSWindow header has two new enumerations (NSWindowUserTabbingPreference, NSWindowTabbingMode) and several new properties. Please examine the header for some detailed comments on what the new methods are for.

API Adoption

    •    What should an application which works well with out-of-the-box window tabbing do? - In general, nothing has to be done. A non-NSDocument based application may wish to support the "+" button by implementing newWindowForTab: somewhere in the responder chain.
    •    What should an application which already has support for tabbing do? - The application should explicitly opt-out of automatic window tabbing by calling [NSWindow setAllowsAutomaticWindowTabbing:NO]. It should respect the userTabbingPreference and create tabs based on the General Flow described below.
    •    What should an application do to customize the standard tabbing behavior? - See the detailed Behavior section below for how the properties interact with each other.

General Flow

The behavior depends on the new system preference under the Dock section to allow tabbing: Always / In Full Screen Only [Default] / Manually. Holding down option, in general, will invert the standard behavior. For each option:

When In Full Screen Only [Default]:

* When in Full Screen all windows opened will prefer to tab, including menu items (Cmd-N, Open Recents, etc), the open panel, and opening documents from Finder.
* When in Full Screen Holding down option will prefer to window [in a new space] instead of a tab
* When on the Desktop things work exactly as they always have, with the additional ability to create tabs manually. See Manually.

When Always:

* When on the Desktop or in Full Screen opening similar windows should prefer to always tab, including menu items (Cmd-N, Open Recents, etc), the open panel, and opening documents from Finder.
* Holding down the option button will prefer to create a window instead of a tab.

When Manually:

* When on the Desktop or in Full Screen opening windows will prefer to just create a normal window.
* Holding down the option button will prefer to create a tab instead of a window.


The userTabbingPreference is a representation of the system preference for tabbing. Applications that already explicitly adopt tabbing, including ones that do not use automatic window tabbing, should read the value of the userTabbingPreference before showing a window to determine if a regular show of a window should prefer to tab with other windows, or be shown in a new window.

[NSWindow allowsAutomaticWindowTabbing] is a way for an application to opt-out of automatic window tabbing. An application that opts out will not get the standard menu items that perform tabbing. The default value for allowsAutomaticWindowTabbing will be YES for all applications except for some that are specifically black-listed out. Those apps can explicitly adopt automatic window tabbing by setting the value of allowsAutomaticWindowTabbing to YES early in the application bring up (in applicationWillFinishLaunching).

A window’s tabbingMode always defaults to NSWindowTabbingModeAutomatic. When the tabbingMode is set to NSWindowTabbingModeAutomatic, and [NSWindow allowsAutomaticWindowTabbing] is YES, the system will automatically tab together similar windows based on tabbingIdentifier. Automatic window tabbing will attempt to tab together windows based on the userTabbingPreference, and how the window was created (based on the logic in “General Flow of Automatic Window Tabs”). When the tabbingMode is set to NSWindowTabbingModeAutomatic, and [NSWindow allowsAutomaticWindowTabbing] is NO, no automatic window tabbing will happen.

A window’s tabbingMode can explicitly be set to NSWindowTabbingModePreferred to allow the window to tab together with other similar windows based on the tabbingIdentifier. This can be set anytime an application wants a window to become in a tab. For instance, it can be set to NSWindowTabbingModePreferred for a window created by a Cmd-T shortcut to always create a window in a tab, regardless of any other system settings, and regardless of the userTabbingPreference. It is up to an application to properly respect the userTabbingPreference and set NSWindowTabbingModePreferred only at appropriate times.

A window’s tabbingMode can explicitly be set to NSWindowTabbingModeDisallowed to explicitly disallow window tabbing. It is up to an application to properly respect the userTabbingPreference and set NSWindowTabbingModePreferred only at appropriate times based on the logic in “General Flow of Automatic Window Tabs”.

A window’s tabbingMode is only checked when a window is about to be shown, and the tabbingMode should be updated before the window is ordered in.

New Button

The plus button will be shown if newWindowForTab: is implemented in the responder chain. NSDocumentController informally implements newWindowForTab:, but only returns YES from respondsToSelector: for this selector if the self.documentClassNames.count > 0 and if the app has a default new document type. In other words, it only responds to it if NSDocument has at least one registered document class name which can be edited.

NSWindow Actions

An application can utilize the standard window tabbing actions to select tabs, merge them into one window, etc: -selectNextTab:, -selectPreviousTab:, -moveTabToNewWindow:, -mergeAllWindows:, -toggleTabBar:.

By default, applications with automatic tabbing will get standard tab menu items added under the Window menu that are hooked up to these actions. However, an app may wish to add contextual menu options that perform the actions. Or, an application which opts-out of automatic tabbing (by setting NSApp.allowsAutomaticWindowTabbing=NO) may still wish to participate in tabs.

To validate the above actions, NSWindow will perform the validation inside its implementation of - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item;, but only if the selector matches one of the above items.


Prior to macOS 10.12, NSAnimationEaseOut was reversed. It would perform an "ease in" animation beginning at the final value and ending at the initial value. For apps linked on or after macOS 10.12, NSAnimationEaseOut now describes a curve beginning at the initial value and ending at the final value, that slows down towards the end.


NSImage now supports multiple representations to support different user interface layout directions.

This can be configured in Xcode for images loaded through asset catalogs. If you are building an image programmatically, note that NSImageRep gains a layoutDirection property. layoutDirection may take one of three values: NSImageLayoutDirectionUnspecified, NSImageLayoutDirectionLeftToRight, NSImageLayoutDirectionRightToLeft. NSImageLayoutDirectionUnspecified means that image rep is equally appropriate for left-to-right and right-to-left layout directions. It is the default value for new image reps.

When drawing an NSImage the correct layout direction is inferred based on the prevailing drawing conditions. This is the case for example inside a view's -drawRect: implementation. In some circumstances it is necessary to manually specify the desired layout direction. This can be accomplished by specifying the NSImageHintUserInterfaceLayoutDirection in the hints dictionary passed to NSImage's draw or rep selection methods.


NSColorSpace now includes support for the “display P3” color space, which has standard DCI-P3 primaries, a D65 white point, and the same gamma curve as the sRGB IEC61966-2.1 color space. It is a canonicalization of the new iMac display profiles that is useful for tagging wide color gamut content.
+ (NSColorSpace *)displayP3ColorSpace;
We also have a corresponding convenience constructor in NSColor:
+ (NSColor *)colorWithDisplayP3Red:(CGFloat)r green:(CGFloat)g blue:(CGFloat)b alpha:(CGFloat)a;

NSColorSpace also exposes sRGB color spaces that enable specifying colors outside of the 0..1 range:
+ (NSColorSpace *)extendedSRGBColorSpace;
+ (NSColorSpace *)extendedGenericGamma22GrayColorSpace;
These provide extended versions of existing color spaces sRGBColorSpace and genericGamma22GrayColorSpace.

To provide consistency with UIColor, the behaviors of the following methods (all introduced in 10.9) have been modified to accept extended color component values. If red, green, blue, or saturation, brightness, or white values are outside of the 0..1 range, these will create colors in the extended sRGB or extendedGenericGamma22GrayColorSpace color spaces:
+ (NSColor *)colorWithWhite:(CGFloat)w alpha:(CGFloat)a;
+ (NSColor *)colorWithRed:(CGFloat)r green:(CGFloat)g blue:(CGFloat)b alpha:(CGFloat)a;
+ (NSColor *)colorWithHue:(CGFloat)h saturation:(CGFloat)s brightness:(CGFloat)b alpha:(CGFloat)a;

Finally, we have the following new API in NSColor to enable creation of RGB-based colors from HSB component values using an arbitrary color space. An exception will be raised if the color model of the provided color space is not RGB:
+ (NSColor *)colorWithColorSpace:(NSColorSpace *)space hue:(CGFloat)h saturation:(CGFloat)s brightness:(CGFloat)b alpha:(CGFloat)a;

NSWindow deep buffer support for wide color monitors

On monitors that support wide color, NSWindow automatically increases the default depth of associated backing stores and offscreen buffers. This can be overridden by setting NSWindow.dynamicDepthLimit = NO, and also setting NSWindow.depthLimit to the desired value. The supported depths are NSWindowDepthTwentyfourBitRGB, NSWindowDepthSixtyfourBitRGB, and NSWindowDepthOnehundredtwentyeightBitRGB. NSWindowDepthTwentyfourBitRGB is the historical default value, and the value used for monitors deemed insufficiently wide. NSWindowDepthSixtyfourBitRGB is the new default for wide monitors, like the P3 panels in the current iMacs. AppKit automatically adjusts the bitdepth of layer backing stores to match the window they are hosted in. This can be overridden on a layer by layer basis using CALayer.contentsFormat.

NSImage support for wide color image reps

NSImage will now use colorspace to disambiguate otherwise identical image reps. For example, on a system with Display P3 output colorspace NSImage will favor an NSBitmapImageRep whose colorspace is display P3, over an otherwise identical NSBitmapImageRep whose colorspace is sRGB.

The colorspace of an image rep can be set using the existing colorSpace property of NSBitmapImageRep, or by configuring the appropriate fields in the asset catalog inspector in Xcode.

Colors in RTF Files

Colors are now preserved in RTF files with a lot more fidelity, by recording the color space and writing count components with more precision. Among other things this enables deep colors to be saved in RTF files.

The extensions to the RTF spec that enable this will be published shortly.

NSDisplayGamut - New since WWDC seed

Some displays support a wide gamut colorSpace. By default, a window inherits its colorSpace from its display, so some windows support wide gamut colorSpaces as well. In 10.12, we've added a facility to check for a wide gamut screen or window so that, for example, the right image assets can be selected.

The NSDisplayGamut enumeration defines buckets for sRGB and p3.
typedef NS_ENUM(NSInteger, NSDisplayGamut) {
NSDisplayGamutSRGB = 1,
NSScreen and NSWindow have a method to check if the receiver is capable of representing the given display gamut.
- (BOOL)canRepresentDisplayGamut:(NSDisplayGamut)displayGamut;
Asset selection is one intended use for this API. If you have assets of varying gamut, start with the richest and ask your destination whether it can represent it. If you need to do asset selection without a known destination, use the first screen in NSScreen's screens array.
if ([window canRepresentDisplayGamut:NSDisplayGamutP3]) {
bestAsset = P3Asset;
} else {
bestAsset = sRBGAsset;

NSColorList - New since WWDC seed

NSColorList has a new API which enables saving color lists using the secure keyed archiving format. This format is preferred, since in addition to being more secure, it is more complete than the older unkeyed format, enabling archiving of colorspace-based colors. Files saved is this format can be read back as early as 10.11. The API is also available back to 10.11.

Like the existing writeToFile: method, specifying a nil destination causes the color list to be saved to the user's colorlists directory. This also adds the color list to availableColorLists, using the name of the color list.
- (BOOL)writeToURL:(nullable NSURL *)url error:(NSError **)errPtr;
At this point, use of the existing writeToFile: method is discouraged.

NSColorPanel writes color lists that are created or edited using the color palette picker with this modern format.


The weight for +[NSFont boldSystemFontOfSize:] is changed to NSFontWeightBold to match the instance returned from +systemFontOfSize:weight: with NSFontWeightBold.


The role of -invalidateCharacterCoordinates is clarified in the header comment. NSTextView is updated to adopt the new behavior.


The menu indicator inside the token is now displayed on the left of title when -userInterfaceLayoutDirection is NSUserInterfaceLayoutDirectionRightToLeft.


Just like on iOS, NSLayoutManager now renders NSLinkAttributeName with underlined blue color without any NSTextView attached on macOS for apps linked with 10.12 SDK or later.


With the change for NSLinkAttributeName rendering for NSLayoutManager, NSTextField now renders the link without the field editor.

NSTextView - New since WWDC seed

With macOS Sierra, NSTextView is transitioning to a new modern object ownership policy that is consistent throughout in behavior and aligned with the Automatic Reference Counting.

In previous macOS releases, NSTextView was using dual ownership policies. With the default ownership mode, NSTextView was retained by its text container forming a reverse ownership tree structure with the NSTextStorage at the root acting as the main owner of the entire object network. The secondary ownership mode was designed for developer convenience and used only by instances initialized by -[NSTextView initWithFrame:]. With the initializer, NSTextView transparently allocated the entire TextKit object network including NSTextContainer, NSLayoutManager, and NSTextStorage. In the mode, NSTextView also retained NSTextStorage effectively creating a circular reference. To workaround the circular reference issue, NSTextView was explicitly counting its references when operating in the convenience mode. This dual ownership issue was making NSTextView not compatible with the ARC weak storage.

With the new ownership policy, we are simplifying the ownership model vastly with just a single mode serving all circumstances. The ownership policy between TextKit objects are unchanged. NSTextStorage owns a list of NSLayoutManagers, and each layout manager owns a list of NSTextContainers. There are two main differences from the default mode in the previous policy: NSTextContainer weakly referencing its NSTextView and each text view always strongly referencing its NSTextStorage. With this new policy, we can serve the flexible TextKit object network as well as NSTextView's convenient behavior freeing developers from maintaining the NSTextStorage reference.

For compatibility, there is a class method controlling the ownership policy introduced, +[NSTextView stronglyReferencesTextStorage]. It returns YES by default, and all instances initialized by a class returning YES operate in the new ownership policy. You can create a subclass of NSTextView overriding the factory method if needed to work in the older ownership policy. Note that such instances are not compatible with the ARC weak storage.