Some of the major topics covered in this section include:
- Responsive scrolling
- Spaces and multiple screens
NSStackView
NSAppearance
and light content controls- Sheet presentation
- Export as PDF
- Layer-backed view updates
- Tagging support in
NSSavePanel
NSTableView
/NSOutlineView
updates- Occlusion
NSSharingService
NSNibLoading
Sheet API has been moved from NSApplication
to NSWindow
. In this move, a number of changes to the API have been made. First is the use of blocks as completion handlers, rather than delegation.
Rather than presenting a sheet:
[NSApp beginSheet:mySheet modalForWindow:docWindow modalDelegate:nil didEndSelector:nil contextInfo:nil];
This will instead be:
[docWindow beginSheet:mySheet completionHandler:nil];
Likewise, when handling the ending of a sheet, a separate method was needed to act as the endSelector
:
[NSApp beginSheet:mySheet modalForWindow:docWindow modalDelegate:self didEndSelector:@selector(didEndSheet:returnCode:contextInfo:) contextInfo:nil];
- (void)didEndSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
[sheet orderOut:self];
NSLog(@"Good bye sheet.");
}
This will instead be handled in the completionHandler
block:
[docWindow beginSheet:mySheet completionHandler:^(NSModalResponse response) {
NSLog(@"Good bye sheet.");
}];
In this example, you’ll also notice that -orderOut:
no longer needs to be called in the completion handler. If you do not dismiss the sheet, it will be done for you after the completion handler finishes.
NSModalResponse
is a new typedef
in NSApplication
created with an enum
of modal responses. NSModalResponseStop
, NSModalResponseAbort
, and NSModalResponseContinue
are added in replacement of the deprecated NSRunStoppedResponse
, NSRunAbortedResponse
, and NSRunContinuesResponse
.
NSWindow
also adds two more modal responses: NSModalResponseOK
and NSModalResponseCancel
(which are replacements for NSPanel
's NSOKButton
and NSCancelButton
).
A sheet's parent (the window or sheet it is attached to), can now be retrieved with -[NSWindow sheetParent]
. This relationship is maintained from the time the sheet is begun with -beginSheet:…
to when it is ordered out.
Another change brought by the moving of this API is queued and critical sheets. Previously, attempting to show a sheet on a window that already has a sheet would result in a 'Beep' to the user, a loss of contextInfo
's memory, and no return call to the modalDelegate
. The new NSWindow
API will queue the second sheet if there is already a sheet present on the window. Once the first sheet is ended and ordered out, the second sheet will be brought down. Queued sheets can be ended ahead of time; so that if a queued sheet becomes unnecessary before the current sheet ends, the queued sheet doesn't have to be presented later. Critical sheets are sheets that are time sensitive and critical to the user; these will skip the queue and be presented on top of an existing sheet, if necessary. Sheets attempted to be presented while a critical sheet is up will be queued like normally; and after the critical sheet is dismissed, the previously presented sheet and queued sheets will be able to be interacted with again.
NSApplication
's sheet API will continue to work as it did before, without the ability to queue sheets.
NSAlert
's -beginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo:
has been deprecated in favor of -beginSheetModalForWindow:completionHandler:
. Through its use of NSWindow
's new sheet API, alerts with an alert style of NSCriticalAlertStyle
will be presented as critical sheet.
NSAlertFirstButtonReturn
, etc are marked as additional NSModalResponse
s used by -beginSheetModalForWindow:completionHandler:
and -runModal
. -[NSAlert runModal]
is declared as returning an NSModalResponse
(a typedef
of NSInteger
).
NSAlert
's Functional API and -alertWithMessageText:defaultButton:alternateButton:otherButton:informativeTextWithFormat:
has been deprecated. These creation methods have used different return codes from modern alert API; these old return codes (NSAlertDefaultReturn
, NSAlertAlternateReturn
, etc.) are also deprecated. NSAlert
and its properties should be used to create an alert instead.
NSSlider
, NSStepper
, and NSLevelIndicator
use the set NSFormatter
to format the result of -stringValue
as well as retrieve the value set through -setStringValue:
.
If there is no set formatter, the value is formatted to an NSString
with %g
.
Before 10.9, overriding -constrainScrollPoint:
aided in allowing developers to center (or use any custom positioning) a document within a scroll view. This works for constraining scrolling; however, constraining the changes resulting from an animation of a change in magnification requires knowledge of the size of the bounds. For this, NSClipView
now has -constrainBoundsRect:
. This comes with the deprecation of -constrainScrollPoint:
, as it can handle a superset of the problems that -constrainScrollPoint:
could.
The order of cells in NSMatrix
is right-to-left layout when -[NSApplication userInterfaceLayoutDirection]
returns NSUserInterfaceLayoutDirectionRightToLeft
. This can be disabled or forced in IB by switching the Control's 'Mirror' value in IB.
PPD access is deprecated through NSPrinter
's table methods (-statusForTable:
, -stringForKey:inTable:
, etc). PMPrinter
API should be used instead.
NSSliderCell
exposes API to support appearance customization:
-drawTickMarks
is an override point to customize the drawing of tick marks.-barRectFlipped:
returns the rectangle in which the slider bar is drawn.- Overriding
-drawBarInside:flipped:
will actually override bar drawing. NSSliderCell
's-knobRectFlipped:
can be called directly if needed.
On apps linked against 10.9, the values returned by the dimensional methods (and passed into the drawing methods) are fitted to the size of default slider artwork. Any custom sliders should be sure to either override the dimensional methods with valid results for their custom artwork, or at the very least consider this fitting inside of -drawBarInside:flipped:
and -drawKnobInside:flipped:
. The dimensions returned by the default slider cell may also change in future releases, so they should not be assumed to remain constant. For binary compatibility, in apps linked before 10.9, NSSliderCell
’s methods return and are passed the legacy, non-fitted rects.
Linear NSSlider
s now support right-to-left configuration when -[NSApplication userInterfaceLayoutDirection]
returns NSUserInterfaceLayoutDirectionRightToLeft
. This can be disabled or forced in IB by switching the Control's 'Mirror' value in IB.
NSSliderCell
no longer receives an additional call to -continueTracking
after the -stopTracking
call.
NSSlider
and NSSliderCell
have formal deprecations for previously obsolete methods:
-setImage:
-image
-setKnobThickness:
-setTitleCell:
-titleCell
-setTitleColor:
-titleColor
-setTitleFont:
-titleFont
-setTitle:
-title
NSStackView
is a new class in OS X 10.9. It is used to layout horizontal or vertical stacks of views using auto layout. Necessary constraints will automatically be created and modified when adding and removing views from a stack view to maintain a cohesive layout. This behavior is extended by customizing various properties of the stack view and the views it holds. Decreasing the clipping resistance priority allows the stack view to become smaller than the the minimum required to hold the provided views. Depending on the visibility priority associated with the internal views, they may either overflow and clip off the side, or drop from the view hierarchy. These dropped views are still retained by the stack view, and will be reattached if the stack view becomes the necessary size. Views can be forced to be dropped or reattached by setting the necessary visibility priority.
Note that NSStackView
's hugging and clipping resistance priorities are distinct from NSView
's contentHugging
and compression resistance priorities. Since stack views have no intrinsic content sizes, contentHugging
does not affect it. However, NSStackView
's hugging priority is the priority at which the StackView wants its internal spacing to be at a minimum and "hug" its contained views. The clipping resistance priority is used to prevent the clipping of the contained views; a value less than NSLayoutPriorityRequired
means the stack view can become less than the minimum size required to hold all of the its views.
Keep in mind that the default hugging priority of NSStackView
is NSLayoutPriorityDefaultLow
(250
). If you add views with hugging priorities of the same value, the constraints can be ambiguous, causing unexpected layouts such as oddly wide or tall views. Fixing these issues can be as simple as tweaking the stack view’s hugging priority, the view’s content hugging priority, or by adding explicit size constraints on the view.
The view hierarchy that NSStackView
manages is private. Additional subviews and constraints can be added to the stack view itself, but should not be added to its private views. These views should not be assumed to remain consistent in future releases, nor should they be assumed to be encoded or decoded with NSCoder
. Because external constraints can be added to the views you add to a stack view, there should be no need to manipulate or measure these private views.
NSTabView
uses the contentCompressionResistancePriority
in the orientation of the tabs to prevent clipping of tabs. Top and Bottom tabs will use the horizontal contentCompressionResistancePriority
; left and right tabs will use the vertical contentCompressionResistancePriority
.
NSUnscaledWindowMask
is formally deprecated.
AppKit has a new API to notify an application if its windows are visible to the user on screen. If a window is not visible to the user then it is occluded.
There are two sets of methods; one set on NSApplication
and one set on NSWindow
. Both sets include a delegate method, an NSNotification
, and a method to query the current state. To determine if any part of your application is visible, your application delegate can implement the method like this:
- (void)applicationDidChangeOcclusionState:(NSNotification *)notification
{
if ([NSApp occlusionState] & NSApplicationOcclusionStateVisible) {
// Visible
} else {
// Occluded
}
}
When the delegate method is called or the notification is posted, use either -[NSApplication occlusionState]
or -[NSWindow occlusionState]
to retrieve the current occlusion state of the application or window. Note that the result of this method is a bitfield, so the appropriate way to check for visibility is to use the bitwise-AND operator. Do not use the equality operator.
Windows are considered occluded if their entire content, including title bar and tool bar, is 100% covered by another opaque window. Windows are also occluded if they are ordered off screen, minimized to the dock, or on another space. Partial occlusion counts as “visible.” An application is only considered occluded if all windows owned by the application are occluded. That is, if any part of any window is visible, then the application is visible.
If your application has no windows except the menu bar, then your application is considered occluded. However, if your application uses an NSStatusItem
, then the window that displays the status item is considered owned by your application and your application will not become occluded while the status item is visible.
This API can be used for increasing the performance of your application, including power, CPU, and network efficiency. For example, when your application is invisible to the user, it might cease expensive operations like retrieving data over the network or drawing an animation. You may also decide to trigger the start of expensive work when notified that the application or window has become visible.
The system reserves the right to delay notification of visibility during certain performance-critical periods. For example, exposing all windows on the system when the user enters Mission Control. In these cases the system will favor responsiveness to the user, and applications will be notified after the performance critical period has finished.
In 10.9, NSMenu
has better support for views using auto layout. If the top-level view set on the menu item has translatesAutoresizingMaskIntoConstraints
set to NO
, the menu item will establish a required LeadingX constraint that position the view in the menu, and another required width constraint that sizes it equal to the menu. The height is the responsibility of the view.
If translatesAutoresizingMaskIntoConstraints
is YES
, the behavior is as it was in previous releases.
Window resize cursors now correctly reflect the minimum and maximum window sizes as determined by auto layout.
NSPopUpButton
's cellSize
method no longer considers the width of the key equivalent, which has never been drawn in OS X anyways.
In 10.9, View-based NSTableView
s have been optimized under auto layout to improve scrolling performance. To take advantage of the optimization, do not establish constraints that relate a view within an NSTableView
row to a view outside of the NSTableView
. (This would be difficult to do in any case - if you design your table view rows in IB you should be fine.)
In 10.9, +setActivationPolicy:
now supports NSApplicationActivationPolicyAccessory
.
In 10.9, -[NSWorkspace openURL:]
may show an error dialog on failure, for apps linked using the 10.9 SDK or later. The return value of -openURL:
is unaffected.
For apps compiled with the 10.9 SDK, -[NSWindow setFrame:display:]
and -[NSWindow setFrameOrigin:]
now perform animations, if invoked in an implicit animation context. To opt out, invoke -[NSWindow setFrame:display:animate:]
and pass NO
for the animate
parameter.
Before 10.9, NSToolbar would ignore the fullScreenAccessoryViewMinHeight
when NSApplicationPresentationAutoHideToolbar
is set. In 10.9, setting a fullScreenAccessoryViewMinHeight
will cause it to be respected whether AutoHideToolbar
is set or not. If you set a value of 0
, the accessory view will animate in and out as the menu bar animates in or out.
10.9 introduces multiple menu bars, each of which draws the status items. If your status item has a custom view, this view is positioned in one menu bar, and other menu bars get a “clone”, which looks identical. The clones are not exposed in the API.
The clones are drawn by redirecting your custom view’s drawing into another window. This means that your status item should not make assumptions about the drawing destination. For example, it should not assume that a call to -drawRect:
is destined for the view’s window, or that the resolution of the drawing destination matches the resolution of the status item’s screen. You must also not assume that the status item is on any particular display, except as described below.
The clones are only redrawn in NSDefaultRunLoopMode
. This allows the status item to limit highlighting to one display, by driving the run loop in another mode, such as NSEventTrackingRunLoopMode
. For example, if you wish to simulate a menu, you would implement mouseDown: to show your window, and run the run loop in NSEventTrackingRunLoopMode
until you determine that the window should be dismissed. While the run loop is in this mode, only the true status item will redraw. Clone status items will not redraw, and therefore they will not show any highlight applied to the true status item.
When a clone status item is clicked, the clone exchanges locations with the true status item. This means that the location and screen of the status item window is reliable from within -mouseDown:
. You can access this information from your custom view, for example, using [[view window] screen]
to position a window on the same screen as the status item.
In 10.9, segmented controls that have -sendActionOn:
set to NSLeftMouseDownMask
now work correctly.
Prior to 10.9, the NSWindow
method -[NSWindow constraintFrameRect:toScreen:]
was invoked only for windows with NSTitledWindowMask
set in their styleMask
. In 10.9, this method is invoked for all windows. The default implementation does a more limited constraining for non-titled windows, as described in “NSWindow
s constrained to not intersect the menu bar” below.
In 10.9, in support of the new multi-monitor architecture, windows are now constrained to not intersect the menu bar on their containing space. This restriction was already in place for titled windows, but it has been extended to borderless windows whose level is at least NSNormalWindowLevel
but less than NSMainMenuWindowLevel
. This behavior is implemented in -[NSWindow constraintFrameRect:toScreen:]
. You may override that method in an NSWindow
subclass to adjust or prevent this constraining.
The following nib loading methods on NSBundle
and NSNib
have been formally deprecated:
+[NSBundle loadNibFile:externalNameTable:withZone:]
+[NSBundle loadNibNamed:owner:]
-[NSBundle loadNibFile:externalNameTable:withZone:]
-[NSNib initWithContentsOfURL:]
-[NSNib instantiateNibWithExternalNameTable:]
-[NSNib instantiateNibWithOwner:topLevelObjects:]
The ARC-compatible methods introduced in 10.8 should be used instead:
-[NSBundle loadNibNamed:owner:topLevelObjects:]
-[NSNib initWithNibData:bundle:]
-[NSNib instantiateWithOwner:topLevelObjects:]
It is important to note the difference in memory management between the deprecated and new methods. The deprecated methods retained the top level objects of the loaded nib file, requiring the caller to explicitly release them. This is no longer necessary with the new methods because they follow the standard Cocoa memory management rules and autorelease the top level objects. IBOutlet
properties to top level objects should be strong
(retain) to demonstrate ownership and prevent deallocation. Alternatively, one may hold a strong reference to the top level objects array, available as an out parameter on these methods.
In 10.9, NSSharingService
provides some new built-in services:
NSString * const NSSharingServiceNamePostOnTencentWeibo;
NSString * const NSSharingServiceNamePostOnLinkedIn;
NSString * const NSSharingServiceNameUseAsFacebookProfileImage;
NSString * const NSSharingServiceNameUseAsLinkedInProfileImage;
In addition NSSharingService
provides the following new properties:
@property (copy) NSString *menuItemTitle;
@property (copy) NSArray *recipients;
@property (copy) NSString *subject;
@property (readonly, copy) NSString *messageBody;
@property (readonly, copy) NSURL *permanentLink;
@property (readonly, copy) NSString *accountName;
@property (readonly, copy) NSArray *attachmentFileURLs;
Mac OS 10.9 has a new feature called Responsive Scrolling. Responsive Scrolling allows the application to continue to rapidly scroll content even when the application’s main thread is busy doing other work. AppKit accomplishes this by having the document view draw more than what is currently visible during idle (see the Overdraw section in these release notes). The responsive scrolling thread is then free to replace what is on the screen with this previously drawn content. Responsive Scrolling requires one to use an NSScrollView
, NSClipView
and a document view.
By default, AppKit tries to turn on this feature where applicable. The following primary conditions, however, are not compatible with Responsive Scrolling. If any of the following conditions are met, the traditional scrolling behavior is performed.
- The application is primarily a Carbon application
- The documentView has an OpenGL context
- The window alpha is not 1.0
- The application links on 10.7 or prior (the application must link on Mountain Lion or higher to support this feature)
There are some secondary requirements that your NSScrollView
subclass, NSClipView
subclass, or document view must meet for them to be eligible for Responsive Scrolling. These secondary requirement checks may be bypassed by overriding the following new NSView
class method on the view that fails the secondary requirements. You should strive to meet the requirements and only use this override as a last resort.
@interface NSView ()
+ (BOOL)isCompatibleWithResponsiveScrolling;
@end
The list of secondary requirements are:
- Do not override
-scrollWheel:
in anNSScrollView
,NSClipView
subclass, or in the document view. (See the event modal notes in this section) - Do not override
-drawRect:
in anNSScrollView
subclass - Do not override
-lockFocus:
in anNSScrollView
,NSClipView
subclass, or in the document view.
Layer backed secondary requirements:
- The root layer must be either the
NSScrollView
or an ancestor view
Traditional drawing secondary requirements:
copiesOnScroll
must be set toYES
on theNSClipView
- The documentView must override
-isOpaque
and returnYES
Traditionally, each scroll wheel event is uniquely hit tested and then handled. For non-gesture scrolling devices, this is still true. For gesture scrolling devices, this has changed dramatically. Once NSScrollView
receives a scroll wheel event, it goes into a concurrent tracking loop. That is, future scroll wheel events are captured privately and processed on a background thread until the gesture, and any associated animation, is complete. If the user physically performs a consecutive scroll gesture, for responsive tracking purposes, it is considered a continuation of the current gesture and is therefore not hit tested.
You may be able to replace your NSScrollView
, NSClipView
subclass, or document view -scrollWheel:
override with one or more of the following techniques.
- Register for bounds change notifications on the clip view
- Register for the live scroll notifications (see the the ScrollView section)
If you only need to peek at the initial scroll wheel event, then return YES
from +isCompatibleWithResponsiveScrolling
to explicitly opt in to Responsive Scrolling.
While the scroll wheel events are being processed on a background thread, the main thread is periodically requested to synchronize. During this synchronization, the clip views bounds are updated and any required notification are posted. If the main thread is free, it is also asked to perform additional overdraw in the direction of the scroll (see NSScrollView
- Overdraw). The result is that if the main thread is busy and / or cannot synchronize quickly enough, the visibleRect of the document may differ from what the user sees on screen. Also, if there is no existing overdraw content at the scrolled to location, then concurrently moving the content is paused while waiting for the main thread to catch up.
NSScrollView
posts new notifications in response to user initiated scrolling. This may occur due to scroll wheels, scroll gestures, scroller tracking or page up / down animation. These notifications are sent on the main thread.
NSString * const NSScrollViewWillStartLiveScrollNotification;
NSString * const NSScrollViewDidLiveScrollNotification;
NSString * const NSScrollViewDidEndLiveScrollNotification;
If the user action has a known start and end point, the WillStart
and DidEnd
notifications are issued with 0 or more Did
notifications sent in between. If the scroll is an animation (for example rubber banding), the DidEnd
notification is not sent until the animation completes. If the scroll view is performing Responsive Scrolling, multiple consecutive scrolling gestures are grouped together into a single series of LiveScroll notifications bracketed by a single WillStart
/ DidEnd
pair.
Some subviews of the document view do not scroll with the rest of the document. Instead these views appear to float over the document (see NSTableView
floating group rows). The following API makes it easier to work with these types of floating views. Also, NSScrollView
ensures that any scrolling on the non-floating axis is visually performed synchronously with the document content. Note: You are responsible for keeping track of the floating views and removing them via -removeFromSuperview
when they should no longer float. A view may only float on one axis at a time.
- (void)addFloatingSubview:(NSView *)view forAxis:(NSEventGestureAxis)axis;
To facilitate Responsive Scrolling, your document view will be asked to draw portions that are not currently visible to the user. AppKit balances the amount of non-visible content drawn with the amount of memory and power usage such drawing requires. NSScrollView
is then free to visually scroll to any previously overdrawn content during Responsive Scrolling.
If your document view has multiple subviews or you need more control over the overdraw area, your document view needs to implement the methods to ensure that all the appropriate content exists in the requested overdraw area.
The following method is called by NSView
with a rect
for a recommended area that should be fully rendered for overdraw. Override this method and bring in additional subviews and pre-cached content for the rect
in order to perform responsive scrolling. Calling super may be required for some subclasses (such as NSTableView
and NSOutlineView
), so in general, super
should always be called. To suppress overdraw for a particular view (such as NSTableView
), override this method and call [super prepareContentInRect:[self visibleRect]]
.
- (void)prepareContentInRect:(NSRect)rect;
The preparedContentRect
is the area of the NSView
that has full content coverage. In general, this should be called with the area that is filled in fully with views. It should always include the visibleRect
. Set this with a value equal to the visibleRect
to have overdraw start from the visibleRect
and automatically grow larger on idle, as is needed for optimal system performance.
@property NSRect preparedContentRect;
-[NSApplication stopModal]
and -[NSApplication stopModalWithCode:]
can now be called from an NSTimer
or other runloop source. This lifts the restriction requiring abortModal
to be used in these cases.
AppKit reserves the right to use all bits of the styleMask
in NSWindow
, and some are used for private communication with other Apple frameworks. Please do not use undocumented styleMask
bits for your own NSWindow
subclasses.
In 10.9, we have added a feature where each screen gets its own set of spaces, and it is possible to switch between spaces on one screen without perturbing the spaces on the other screens. In this mode, a fullscreen window uses one screen, and leaves the contents of any other screens unchanged.
Each screen now has its own menu bar, and it is possible to show the Dock on any screen, provided you have the Dock set to “Position on Bottom”.
The menu bar has an active appearance on the active screen, which is typically the screen containing the key window. Menu bars on other screens have an inactive appearance.
In this mode, it is desirable for new windows to open on the active screen. In support of this model, +[NSScreen mainScreen]
now returns the active screen, which is slightly different than its prior behavior of returning the screen containing the keyWindow, if any, and the zero screen otherwise.
A window restored at app launch through -restoreStateWithCoder:
will return to its previous location, independent of active screen. A window positioned using -setFrameAutosaveName:
will prefer the active display.
This feature can be disabled by unchecking the preference named “Displays have Separate Spaces” in the Mission Control preference pane in System Preferences. This setting only takes effect after logging out and back in, or restarting. NSScreen
has API to query whether the separate space feature is enabled:
+ (BOOL)screensHaveSeparateSpaces NS_AVAILABLE_MAC(10_9);
When this feature is enabled, windows may not visibly span displays. A window will get assigned to the display containing the majority of its geometry if programmatically positioned in a spanning position. A window will get assigned to the display containing the mouse if the window is moved by the user. A window clips to the edge of the display, whether or not there is another adjacent display.
### Tagging Support in `NSSavePanel`NSSavePanel
provides a field that allows users to specify Tags (a new feature in OS X 10.9) that should be applied to the resulting file. However, since NSSavePanel
isn't responsible for creating the file, your application should adopt new API to ensure the requested Tags are set correctly.
To opt in to NSSavePanel
Tagging support, you should invoke -[NSSavePanel setShowsTagField:YES]
prior to displaying the panel. When the user click Save in the panel, you can get the Tag names they entered by invoking -[NSSavePanel tagNames]
. After creating the file at the requested URL, you should set the requested Tag names on the file by using the NSURLTagNamesKey
API.
If your application does not adopt the above API, NSSavePanel
will still show the Tags field and will attempt to automatically apply the Tags by listening to file system change notifications for a limited duration to detect when your application creates the requested file. However, this technique is imperfect, so you are strongly encouraged to test your application's support for tags in the save panel and adopt the above API if needed.
In OS X 10.9, NSDocument
and NSPrintOperation
provide new API and functionality to aid you in creating an Export as PDF option that is consistent with the rest of the operating system.
NSDocument
has a new standard IBAction
method called -saveDocumentToPDF:
. If your NSDocument
subclass already implements -printOperationWithSettings:error:
, then invoking this method will cause NSDocument
to use the resulting NSPrintOperation
to prompt the user for a location and save a PDF. The resulting PDF export panel will also include certain standard print panel configuration controls that you have enabled (like paper size and orientation) and the first accessory controller from the NSPrintOperation
's NSPrintPanel
.
The default implementation of -saveDocumentToPDF:
simply invokes [self printDocumentWithSettings: @{ NSPrintJobDisposition : NSPrintSaveJob} showPrintPanel:NO delegate:nil didPrintSelector:NULL contextInfo:NULL]
. When invoked with these parameters, the method will invoke -PDFPrintOperation
instead of -printOperationWithSettings:error:
. The default implementation simply invokes [self printOperationWithSettings:@{ NSPrintJobDisposition : NSPrintSaveJob } error:NULL]
, but you can override this method if you need to customize the way your application creates PDFs or to provide a different accessory controller.
If your application doesn't use NSDocument
, you can still use NSPrintOperation
to implement Export as PDF. Prior to OS X 10.9, running an NSPrintOperation
that had its job disposition set to NSPrintSaveJob
and its NSPrintJobSavingURL
set to nil
would result in undefined behavior. However, on OS X 10.9, doing this will cause NSPrintOperation
to display an NSPDFPanel
, prompting the user for a location where it will save the PDF.
Whether or not you use NSDocument
, you can modify the PDF export panel used by NSPrintOperation
by either creating a new NSPDFPanel
with the desired options and accessory controller, or modifying the one that NSPrintOperation
creates automatically.
If your application is unable to use NSPrintOperation
to generate PDFs, you can still use NSPDFPanel
to ensure your application's user interface is consistent with the rest of the operating system. In order to do this, you should first create an NSPDFInfo
object, optionally changing the paperSize and orientation properties. Then you should invoke -[NSPDFPanel beginSheetWithPDFInfo:modalForWindow:completionHandler:]
passing the NSPDFInfo
object you created. When the completion handler is invoked, the given NSPDFInfo
object will be modified with the URL, file extension hidden flag, and Tag names, and rendering parameters that should be used when creating the PDF.
Shoebox-like applications may wish to generate multiple separate PDFs when the user has selected multiple items. To support this, NSPDFPanel
supports the NSPDFPanelRequestsParentDirectory
option. When run with this option, NSPDFPanel
will prompt the user to choose a directory instead of a directory and a document name. The URL of the resulting NSPDFInfo
object will contain the user's chosen directory. You are responsible for appending a file name to this path.
If your application manually runs an NSPDFPanel
but uses NSPrintOperation
to create PDFs, NSPrintInfo
provides -takeSettingsFromPDFInfo:
, which will modify the receiving NSPrintInfo
with all the settings from the given NSPDFInfo
. But remember, if you use NSPDFPanelRequestsParentDirectory
, you must modify the NSPDFPanel
's URL by appending a file name before passing it to -takeSettingsFromPDFInfo:
. If the URL doesn't looks like it points to a directory, the method will throw an exception.
NSDocument
provides the -performActivityWithSynchronousWaiting:usingBlock:
to ensure document concurrent operations are performed and their results presented in a properly serialized manner. Presentation of any alert or error sheet on a document is supposed to be done within an 'activity' block to avoid multiple sheets interfering with each other.
NSDocument
internally presents many alerts on documents and is responsible for making sure this is done within an 'activity' block. However, prior to OS X 10.9, the alert that is displayed when the user edits a locked document was not presented within an 'activity' block. As a result, alerts originating from application-defined 'activities' could potentially interfere with it, often resulting in deadlocks. This has been fixed on OS X 10.9.
Prior to OS X 10.9, NSPathControl
behaved unexpectedly in sandboxed applications when used with a URL within the user's home directory. NSPathControl
would fail to recognize that sandboxing redirects NSHomeDirectory()
to the application's sandbox container. Additionally, the NSPathControl
was given the URL to the user's real home directory, it would fail to recognize that path as home, and would therefore show the entire path up to the root of the volume instead of stopping at the user's home directory. These issues have been fixed on OS X 10.9.
Key Value Observation compliance was dramatically increased for public and some private properties of actual, non sandboxed NSOpen
and Save
panels, including keys affecting other values. For example, if the directory value changes on a save panel, this will cause a KVO notification to be emitted for the URL value as well as the directory value. Sandboxed NSOpen
and Save
Panels do not have the same level of KVO compliance.
In the “On my Mac” mode of the App Centric Open Panel (the open panel shown for applications using iCloud), accessory Views are now hidden by default in and can be revealed by hitting the “Options…” button.
Automatic key loop recalculation is enabled. This not only obviates the need to explicitly recalculate the key loop after modifying a subview of the accessory view but also makes it possible for the accessory view itself to reliably declare itself a key view.
The name of the default system font has changed from LucidaGrande
to .LucidaGrandeUI
. In the vast majority of cases this should not present a problem. However, there is a case where fonts can be unexpectedly decoded from an archive as LucidaGrande
rather than the new system system font. This can cause a variety of subtle issues, including slight changes to the layout of certain button titles. This will occur if you are still using nib files rather than xib files, built them using Xcode 4 or earlier, and they use system fonts in non-standard point sizes. When you change the point size to be non-standard, older versions of Xcode will change the displayed font type from "System" to "Custom", and then it will not be decoded as the new system font on Mavericks. Xcode 5 will correct this problem when opening your nib file, so the UI will automatically show "System", but note that it's still necessary to save the changes.
Channel mapping is deprecated in 10.9, consequently channels should be mapped at a lower level using AudioUnitSetProperty
.
In 10.9, the user may choose to have different preferences for the “Swipe between pages” behavior for mouse and trackpad input devices. It is now possible for this behavior to be enabled for trackpad devices but disabled for mouse devices (or vice versa). By default, swipe between pages is enabled for trackpads and disabled for mice.
AppKit provides the -isSwipeTrackingFromScrollEventsEnabled
method to determine the current user preference. The behavior of this method is now based on the current event (as returned by [NSApp currentEvent]
). If the current event originated from a mouse device, this method returns the user preference for mouse devices; otherwise, it returns the user preference for trackpad devices.
These accessibility constants have been added:
NSAccessibilityMisspelledTextAttribute
was the original attribute to indicate misspelled text. In OS X 10.4, the Cocoa text system added support for NSAccessibilityMarkedMisspelledTextAttribute
, which was used to indicate a word that was visibly marked as misspelled (for example, with a red squiggle underneath); the original MisspelledText attribute could also be used on text that was not visibly marked as misspelled (for example, a misspelled word that was currently being edited by the user).
Typically, a screen reader only wants to vocalize what a sighted user could see, and so the MarkedMisspelledText attribute was adopted by VoiceOver to provide feedback to the user about misspelled text. In OS X 10.9, VoiceOver has entirely stopped using the original MisspelledText attribute, and now only checks for MarkedMisspelledText.
When implementing accessibility for a custom text-editing engine, you should generally provide the MarkedMisspelledText attribute in order to support VoiceOver, especially in OS X 10.9 and later. You may optionally also support the MisspelledText attribute for compatibility with other accessibility clients.
This subrole is similar to the existing NSAccessibilityDefinitionListSubrole
, but is preferred to represent HTML5 objects indicated by the <DL>
tag.
The NSAccessibility
informal protocol now supports a new protocol method, -accessibilityNotifiesWhenDestroyed
.
Prior to 10.9, the only accessible objects that could post accessibility notifications were those that inherited from NSView
, NSWindow
, or NSCell
. An application's custom accessible object, subclassed from NSObject
, could not post notifications.
In 10.9 and later, an application's custom accessible object may post accessibility notifications if it follows the following guidelines:
-
the object must implement
-accessibilityNotifiesWhenDestroyed
to returnYES
. -
the object must post the
NSAccessibilityUIElementDestroyed
notification at appropriate times, typically when the corresponding UI element in the application's visual interface is removed from the screen, and certainly when the accessible object is deallocated. -
the lifetime of the
NSObject
must match the lifetime of the corresponding element in the application's visual interface. It is common for a custom accessible object that acts as a proxy for an onscreen UI element to be autoreleased and deallocated very quickly, immediately after the application responds to a single accessibility request. This is not sufficient to support posting notifications, because any notification observers that are registered on the object will be removed as soon as the object is deallocated. Instead, the application must arrange for an accessible object that refers to a specific UI element to remain allocated as long as that UI element is visible.
The Accessibility API is designed to help make OS X more accessible to users with disabilities. To accomplish this, the API is able to vend all of the strings and values that are displayed onscreen to clients such as VoiceOver. This is critical, especially for book-reading applications, because it allows users who are blind to read and interact with the same content as everyone else.
However, some applications need to be able to prevent their string content from being copied by other applications that use the Accessibility API. It is now possible for an application to tell the Accessibility implementation that some of its content is protected.
There are two steps required to indicate that a particular UI element has protected content:
- use the
NSAccessibilitySetMayContainProtectedContent
API to indicate that this application contains protected content - handle requests for
NSAccessibilityContainsProtectedContentAttribute
in your accessible objects’s-accessibilityAttributeValue:
implementation, returning anNSNumber
containingYES
.
Application UI elements can appear, disappear, or change as a result of mouse movement to certain positions in the content, or other types of user input, such as press or release of a modifier key. This presents several problems for clients of the Accessibility API:
- there is no equivalent accessible way to simulate such mouse triggered events
- there's no way to know when/what happened as a result of mouse rollover
The Accessibility API now offers new features to support transient UI elements.
These accessibility actions should be implemented to present the alternative or default UI.
This API allows an accessibility notification to be posted with a user info dictionary. When transient UI elements are shown or hidden, an application should use this API to post NSAccessibilityLayoutChangedNotification
with a user info dictionary containing a list of the UI elements that have changed.
This notification lets accessibility clients such as VoiceOver know that some UI layout change has occurred. The client application then has the option to decide if it wants to give feedback, auto jump to a new UI, list the new or changed UIs in a menu, or do nothing. The notification can be used by anything that changes UI on screen. As an example, this could be triggered by an explicit NSAccessibilityShowAlternateUIAction
, or by user input such as mouse hovering. Similarly, performing NSAccessibilityShowDefaultUIAction
or mouse exiting a UI element to revert some transient UIs should also cause this notification to fire. The notification can contain a user info dictionary with the key NSAccessibilityUIElementsKey
and an array of elements that have been added or changed as a result of this action.
This notification allows an application to request that an announcement be made to the user by an accessibility client such as VoiceOver. The notification requires a user info dictionary with the key NSAccessibilityAnnouncementKey
and the announcement as a localized string. In addition, the key NSAccessibilityAnnouncementPriorityKey
should also be used to help accessibility clients determine the important of this announcement. This notification should be posted for the application element.
This key is used in the user info dictionary for notifications. The value is an array of elements that are associated with the notification.
This key can be used in the user info dictionary for any notification. This gives the client an opportunity to determine how to handle this notification based on the priority. For example, a developer can pass the priority for NSAccessibilityAnnouncementRequestedNotification
. Clients such as VoiceOver can then decide to speak the announcement immediately or after the current speech is completed. The NSAccessibilityLayoutChangedNotification
is another example where priority can help VoiceOver determine if the UI change requires the VO cursor to go to the new UI.
This key is used in the user info dictionary for notifications. The value is a localized string. This should generally be used in conjunction with the NSAccessibilityPriorityKey
to help accessibility clients determine the important of this announcement.
Returns an array of elements that also have keyboard focus when a given element has keyboard focus. A common usage of this attribute is to report that both a search text field and a list of resulting suggestions share keyboard focus because keyboard events can be handled by either UI element. In this example, the text field would be the first responder and it would report the list of suggestions as an element in the array returned for NSAccessibilitySharedFocusElementsAttribute
.
NSAppearance
is a new class in Mac OS X 10.9. It can be used to access alternate appearances of standard system windows and views. You obtain an NSAppearance
by name using +[NSAppearance appearanceNamed:]
. A new appearance for controls that is appropriate for light backgrounds (such as popovers) is accessible via the name NSAppearanceNameLightContent
. To access the default system NSAppearance
, use the name NSAppearanceNameAqua
.
NSAppearanceCustomization
is a new protocol that NSView
and NSWindow
adopt that allows customization on those objects. To customize the appearance of a window, call -setAppearance:
on the window with your NSAppearance
object. That will cause the window itself to take on the customizations in that NSAppearance
, as well as any view in that window. To customize just a view, call -setAppearance:
on that view. Any specific customization not found in a view's appearance will fall back up to that view's superview, ultimately trying the window's appearance. If a customization is not found at the window level, the default (Aqua) appearance is used. Use the effectiveAppearance
method (part of NSAppearanceCustomization
) to access what NSAppearance
object will be used when drawing that view or window; this takes into account appearances set on superviews and windows.
While drawing views, the +currentAppearance
is set for the drawing thread. To access the current appearance, use:
NSAppearance *currentAppearance = [NSAppearance currentAppearance];
Mac OS X 10.9 now contains global user preference settings for the use of automatic quote and dash substitution. Applications that provide for the entry of free-form text in which typographically correct quotation marks and other punctuation would be appropriate may follow these settings by using the new NSSpellChecker
methods
+ (BOOL)isAutomaticQuoteSubstitutionEnabled;
+ (BOOL)isAutomaticDashSubstitutionEnabled;
and by listening to the following notifications to be notified of changes
NSString *NSSpellCheckerDidChangeAutomaticQuoteSubstitutionNotification;
NSString *NSSpellCheckerDidChangeAutomaticDashSubstitutionNotification;
For applications compiled on 10.9 and later, NSTextViews
by default will automatically follow these settings, unless -setAutomaticQuoteSubstitutionEnabled:
or -setAutomaticDashSubstitutionEnabled:
has been called.
Prior to 10.9, deselecting a row with a cmd-click would call -tableView:selectionIndexesForProposedSelection:
but the resulting selection may not have been used. This has been properly fixed for applications that link on 10.9 and higher, and the resulting selection returned by the delegate will be used.
NSOutlineView
now fully supports Right To Left language layout. This can be achieved in several ways. One can explicitly set the userInterfaceLayoutDirection
in code or in a NIB. Or, if auto-localization is used and the app is linked on 10.9 (or higher), then the userInterfaceLayoutDirection
will automatically be flipped if it differs from [NSApp userInterfaceLayoutDirection]
.
Prior to 10.9, calling -moveRowAtIndex:toIndex:
when the NSTableRowView
being moved (or any subview of the NSTableRowView
) was the first responder, would leave the table in a bad state. This has been fixed for all applications in 10.9. For applications that need to run on platforms prior to 10.9, it is recommended to first make the window the firstResponder
before calling -moveRowAtIndex:toIndex:
(if the row being moved is the firstResponder
).
Prior to 10.9 there was a visual glitch (specifically, a removed NSTableRowView
) when performing a row delete right before a row insertion in the same -beginUpdates
/-endUpdates
block, but only when both animations where either NSTableViewAnimationSlideUp
or NSTableViewAnimationSlideDown
. This has been fixed for 10.9, and applications that need to target prior to 10.9 should ensure they do a different animation for the deletion, or perform the deletion in a separate -beginUpdates
/-endUpdates
block.
Using a View Based TableView with a rowSizeStyle
of NSTableViewRowSizeStyleDefault
will automatically update the rowSizeStyle
of each cell view for tables with the NSTableViewHighlightStyleSourceList
. However, prior to 10.9 the rowSize
style for "header rows / group rows" would always be set to Medium
and Large
, when they should always be Small
regardless of the user setting in System Preferences. This has been fixed in 10.9 for all applications using a View Based TableView.
Using -beginUpdates
/-endUpdates
on a cell based tableview may potentially throw an exception "NSTableView Error: Insert/remove/move only works within a -beginUpdates/-endUpdates block.
" if the cell based table view is layer-backed. This has been fixed for all applications on 10.9 and higher. For prior applications, it is recommended to use a view based NSTableView
when using -beginUpdates
/-endUpdates
, or to not layer-back the table view.
Calling [tableView addTableColumn:]
after a call to [tableView moveColumn:toColumn:]
may through an exception if done in the same call stack level; this has been fixed in 10.9 for all applications. For applications that need to work around this prior to 10.9, be sure to call -addTableColumn:
before calling -moveColumn:toColumn:
.
Calling [outlineView removeItemsAtIndexes:inParent:withAnimation:]
that results in removing an expanded item may have left the item retained by NSOutlineView
for an indefinite amount of time. This has been fixed on 10.9. For applications that need to work around this prior to 10.9, call -collapseItem:
before removing the item.
Hiding and unhiding an NSTableColumn
(via -setHidden:
) will cause the table to automatically resize other table columns to make room for the new table column (or take up slack for the one that was hidden). Previously, this would always attempt to resize columns based on the enclosingScrollView
's visible width. On 10.9 this has been changed to prefer the actual width, in the case of a horizontally scrollable table view.
NSTableView
has a user default to allow all the default animations it does to be slowed down: NSTableViewSlowMotion
YES
/NO
, which can be set with 'defaults' or a command line parameter.
NSView
now exposes a property userInterfaceLayoutDirection
, which is backwards available on 10.8 for NSView
, and 10.7 for NSOutlineView
. userInterfaceLayoutDirection
defaults to [NSApp userInterfaceLayoutDirection].
It is up to a particular view's implementation to properly support Right To Left layout. NSOutlineView
properly implements the Right To Left layout.
NSView
has some new API to ease layer-backed adoption. The new property canDrawSubviewsIntoLayer
allows a parent view to draw all of its subviews into a single layer, when that parent view is layer-backed. This is also sometimes referred to as an “inclusive layer”, as all the children views are drawn inclusively into a single parent layer. Normally, calling -setWantsLayer:YES
on a parent view will create individual layers for that parent view and all individual subviews. However, each individual subview will not have wantsLayer=YES
, but will inherit its own unique layer by virtue of being in a layer-tree. When canDrawSubviewsIntoLayer
is set to YES
, the parent view will draw all subviews into a single layer, and each individual subview will not have an individual layer. The exception is a particular subview which already has wantsLayer set to YES
on it. It is recommended to first call -setCanDrawSubviewsIntoLayer:YES
, and then call -setWantsLayer:YES
to avoid unnecessary work. The reason to use canDrawSubviewsIntoLayer=YES
, is when there is a view hierarchy which can not be refactored to take advantage of the new Mountain Lion 10.8 API of -wantsUpdateLayer=YES
and -updateLayer
. Another reason to use this feature is to collapse multiple layers into a single layer, in order to gain better application performance. It is generally recommended to turn canDrawSubviewsIntoLayer
on only for parent views which are opaque; otherwise text font-smoothing may not look correct. However, it is acceptable to set canDrawSubviewsIntoLayer
to YES
for non-opaque views if no text is drawn, or if text is known to draw into some opaque portion of the view (or subview). Note that turning on canDrawSubviewsIntoLayer
requires the layerContentsRedrawPolicy
to not be NSViewLayerContentsRedrawNever
; otherwise subview invalidation will not work. Please note that calling setLayer: with a custom layer will implicitly cause the layerContentsRedrawPolicy
to be set to NSViewLayerContentsRedrawNever
. This side effect is so AppKit will have a "hands off" approach on custom layers assigned to a view.
Please be aware that using an [NSAnimationContext beginGrouping / endGrouping]
will cause a CATransaction
to commit; this will cause layer-backed views to potentially get a -viewWillDraw
(and a -drawRect:
or -updateLayer
) immediately after the [NSAnimationContext endGrouping]
is called (or [CATransaction commit]
).
Layer-backed NSButtons
in 10.8 would previously not up-scale the image property, and would not properly use the alternate title when the state changed. Also, when a button was shown with no border (and just a title), the focus ring would not draw. NSButtonCell
has been moved to properly use the NSView
and NSCell
focusRingMask*
API. These bugs have been fixed for all applications on 10.9, and any applications providing (or hiding) the focus ring should use the focusRingMask*
methods to provide (or customize) the focus ring.
In 10.8 Mountain Lion, layer-backed views would not invalidate the layer if the size was empty (0,0)
. This has been fixed for applications that link on 10.9 and higher.
Returning [NSNull null]
from NSView
's -animationForKey:
or -defaultAnimationForKey:
will now correctly be interpreted as not doing an animation. Previously, it would incorrectly cause the default CALayer
animation to happen.
NSSplitView
now overrides defaultAnimationForKey:
and returns [NSNull null]
for the subviews
key. This suppresses the subviews animation, which is generally not desired and would be seen as a crossfade.
Layer backed views created by AppKit will now by default have the CALayer
edgeAntialiasingMask
property set to 0
.
There is a new layerContentsRedrawPolicy
of NSViewLayerContentsRedrawCrossfade
. This can be used to do a crossfade of layer contents when the view's frame size changes. For some views, it also is applicable to views which have contents. For instance, one can easily cross fade the string of an NSTextField
with:
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
context.allowsImplicitAnimation = YES;
textField.stringValue = @"Testing from the treehouse";
} completionHandler:nil];
Beginning in Mac OS X 10.9 CoreAnimation layer trees are rendered out-of-process. CoreImage filters attached to layers are not supported in this mode. If you are using CoreImage filters on a layer attached to NSView
, please set the layerUsesCoreImageFilters
property on your view to YES
. When set, the layer tree hosting the NSView
will be rendered in-process. Failure to set this property will result in an exception being thrown when filters are applied to a layer. Note that if you are setting filters using the NSView
properties (backgroundFilters
, compositingFilter
, or contentsFilters
) you do not need to set the layerUsesCoreImageFilters
property.
Prior to Mac OS 10.9 images loaded through +[NSImage imageNamed:]
were retained for the lifetime of the application. For applications linked on 10.9 and later this is no longer the case. Images loaded through +[NSImage imageNamed:]
will still be cached for a brief time.
Beginning in Mac OS X 10.9 -[NSView allocateGState]
and -[NSView releaseGState]
are no ops. These methods were seldom used. Additionally, methods that relied on the side effects of these methods, specifically -[NSView gState]
and -[NSWindow gState]
will now always return 0
. The method -[NSView renewGState]
will continue to be invoked as it has in the past, when the view's location in the window has changed.
Beginning in Mac OS X 10.9, NSImage
will invoke -[NSImageRep draw]
with the current compositing operation set to NSCompositeSourceOver
. This matches the behavior of drawing in NSView. Prior to this, -[NSImageRep draw]
would be invoked with either the compositing operation passed to NSImage
itself, or NSCompositeCopy
, depending on the circumstances.
If you have subclassed NSImageRep
, you may now depend on NSCompositeSourceOver
being set when your -draw
method is invoked. Likewise, if you are supplying a block to either +[NSImage imageWithSize:flipped:drawingHandler:]
or -[NSCustomImageRep initWithSize: flipped:drawingHandler:]
you may also depend on NSCompositeSourceOver
being the current composite operation when your block is invoked.
Note that if you are deploying to previous OSes (or wish to use a non source-over composite operation) you should explicitly set the drawing operation. This can be done using the -[NSGraphicsContext setCompositeOperation:]
API.
Prior to Mac OS X 10.9, returning YES
from a layer delegate's -layer:shouldInheritContentsScale:fromWindow:
method would cause AppKit to update the contentsScale
property of a CALayer
, and then invoke -setNeedsDisplay:YES
on the NSView
that contained that CALayer
. In Mac OS X 10.9, the layer itself will be marked needing display. This fix is conditionalized against apps that have been linked on Mac OS X 10.9 or later.
The following NSOpenGL
pixel format creation options should be considered deprecated, and have been deprecated by the underlying OpenGL libraries for some time. Their effects should be considered undefined, and their use avoided.
NSOpenGLPFAOffScreen
NSOpenGLPFAFullScreen
NSOpenGLPFASingleRenderer
NSOpenGLPFAWindow
NSOpenGLPFACompliant
NSOpenGLPFAPixelBuffer
NSOpenGLPFARemotePixelBuffer
NSOpenGLPFARobust
NSOpenGLPFAMPSafe
NSOpenGLPFAMultiScreen
The OpenGL library option NSOpenGLGOResetLibrary
should also be considered deprecated, and its use avoided.
The following methods on NSOpenGLContext
should also be considered deprecated. Note that support for these methods no longer exists for many hardware configurations, and their usage may result in crashes.
- (void)setFullScreen;
- (void)setOffScreen:(void *)baseaddr width:(GLsizei)width height:(GLsizei)height rowbytes:(GLint)rowbytes
- (void)copyAttributesFromContext:(NSOpenGLContext *)context withMask:(GLbitfield)mask
- (void)createTexture:(GLenum)target fromView:(NSView *)view internalFormat:(GLenum)format
When trying to create a full-screen context, use a fullscreen NSOpenGLView
instead.
To render offscreen, please see the documentation regarding OpenGL FrameBufferObjects
(FBOs) and glReadPixels
.
Finally note that the entirety of the NSOpenGLPixelBuffer
class should be considered deprecated. Use IOSurface
in conjunction with GL framebuffer objects as a replacement.
NSColor
now provides three new methods for easier reuse of code that uses UIColor
on iOS:
+ (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;
These create colors that are compatible with sRGB. However, where you have a choice, it's better to use the methods such as +colorWithSRGBRed:green:blue:alpha:
that specify the color space explicitly.
There is a UI behavior change introduced for NSTokenField
in Mac OS X 10.9. Adjacent Tokens are not longer visually connected when selected. As a dragging source, NSTokenField
now removes the tokens drag/dropped with NSDragOperationGeneric
(moving the selection).
Setting attributed placeholder string via -setPlaceholderAttributedString:
renders the attributed string value while focused.