Document Generated: 2012-07-10 15:55:03 -0700
OS X Release Notes Copyright © 2012 Apple Inc. All Rights Reserved.


OS X Mountain Lion 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.

This document has been updated for the GM release of OS X 10.8 Mountain Lion.

Some of the major topics covered in this document:


Please also refer to the Foundation release notes for notes on other important changes in 10.8.

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

Marking updated APIs in headers

New APIs in headers are marked with decorations that include references to "10_8":
 NS_AVAILABLE_MAC(10_8), NS_AVAILABLE(10_8, <iOS Release>), NS_CLASS_AVAILABLE(10_8, <iOS Release>), NS_ENUM_AVAILABLE(10_8)
or the construct:
 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
...
#endif
Deprecated APIs are marked with:
 NS_DEPRECATED_MAC(<Release when introduced>, 10_8)

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_0 577
...
#define NSAppKitVersionNumber10_6 1038
#define NSAppKitVersionNumber10_7 1138
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_6) {
/* On a 10.6.x or earlier system */
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_7) {
/* On a 10.7 - 10.7.x system */
} else {
/* Mountain Lion or later system */
}
Special cases or situations for version checking are also 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 582.1

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:]).


NSDocument Support for iCloud

In 10.8, NSDocument-based applications with a ubiquity-container-identifiers entitlement gain new functionality and UI to facilitate iCloud document management.

When iCloud is enabled and an application is first launched or re-activated and no windows are visible or being restored, instead of creating a new Untitled document, NSDocumentController will display a non-modal open panel showing the user's iCloud library. From there an application can either open an existing document from iCloud or the local file system, or create a new document. To support this new non-modal open panel, NSDocumentController has added -beginOpenPanelWithCompletionHandler: and -beginOpenPanel:forTypes:completionHandler:. Note that currently the former method will only run the open panel non-modally when iCloud is enabled.

If your application overrides -[NSDocumentController openDocument:] and invokes -URLsFromRunningOpenPanel, you should switch to calling -beginOpenPanelWithCompletionHandler: instead.

If your application overrides -[NSDocumentController runModalOpenPanel:forTypes:] to customize the open panel, including adding an accessory view, you should also override -beginOpenPanel:forTypes:completionHandler: and do the same customization there. For compatibility NSDocumentController will continue to invoke the former if it is overridden when the latter isn't. As a result, the panel will be run modally instead of non-modally, giving your users a suboptimal experience.

iCloud-enabled applications also gain UI to facilitate moving documents into the cloud via the move and save panels. There is also a shortcut in the document titlebar menu to quickly move the document to iCloud. This menu item uses a new IBAction method on NSDocument: -moveDocumentToUbiquityContainer:. Also, as mentioned in the section on Drafts, new documents can get autosaved directly to the application's iCloud container, depending on the user's preference.

NSDocument also provides a new conflict resolution UI that allows users to inspect the contents of each conflict and save each conflicting version as a separate file, if they wish.

Applications that do not wish to use these features for any or all of their NSDocument subclasses can override +[NSDocument usesUbiquitousStorage] and return NO. If all of the application's declared NSDocument subclasses return NO from this method, then NSDocumentController will never show the new non-modal open panel.

NSDocument Versions Preservation Optimization

In Mac OS 10.7, when NSDocument decided that its file deserved to be preserved as a version prior to saving it would synchronously copy the file to perform the preservation. For significantly large files this could cause long hangs that interrupt the user's workflow. In applications linked on or after 10.8, NSDocument can avoid this hang by leveraging the 'backup' file that gets created during safe-saving.

When the current file's contents need to be turned into a version prior to saving, the file will get moved out of the way prior to the newly written file overwriting it. After the new file is successfully saved in the old file's place, a version can be created from the old file without requiring an expensive copy.

NSDocument uses -[NSDocument backupFileURL], a new method in 10.8, to control this behavior. This method only returns a URL when the current file needs to be preserved. When this method returns non-nil, -writeSafelyToURL:ofType:forSaveOperation:error: must ensure that the original contents of the file exist at that location prior to returning. Failing to do so is tantamount to data loss, since the user will be unable to revert to their previous versions. If your NSDocument subclass overrides -writeSafelyToURL:ofType:forSaveOperation:error: and doesn't call super, when you link against 10.8 you must ensure that your implementation obeys this rule. Alternatively, you can override -backupFileURL and return nil to disable this optimization. By doing so, -saveToURL:ofType:forSaveOperation:completionHandler: will fall back to the old synchronous copy technique. Applications that do saving in-place and don't use the safe-saving technique will almost always want to disable this optimization unless the cost of creating the 'backup' file is significantly less than a copy.

You should not override -backupFileURL to return a custom URL. Your override should either call super or return nil.

Sometimes versions are preserved after the new file is written, such as when the user chooses File > Save. In this scenario, the backup file optimization is not possible, so a copy is still necessary. However, for applications linked on 10.8, NSDocument will perform this copy on a background thread, leaving the main thread unblocked. To avoid corrupting these versions by modifying the file during this asynchronous copy, you should make sure that any direct access to your document's file is done with -performSynchronousFileAccessUsingBlock: or -performAsynchronousFileAccessUsingBlock:.


Debugging -performActivityWithSynchronousWaiting:usingBlock:, -performSynchronousFileAccessUsingBlock:, and -performAsynchronousFileAccessUsingBlock:

In Mac OS 10.7, NSDocument added these three APIs to ensure proper serialization of file access and user activity when using asynchronous saving. When an asynchronous activity or file access fails to properly invoke its completion handler, subsequent uses of these APIs wait forever. Unfortunately, due to the asynchronous nature of these APIs, the backtrace of these hangs usually doesn't provide enough information to debug the problem and identify the unterminated operation.

In 10.8, NSDocument provides a tool to help you more easily debug these problems. If your application is hanging in -performActivityWithSynchronousWaiting:usingBlock: or -performSynchronousFileAccessUsingBlock:, break in the debugger and execute this command:
po _NSDocumentSerializationInfo()
The output of this command will contain a listing of all unterminated invocations to these serialization APIs, including the document instance in question, the backtrace where the API was invoked, the type of serialization (file access vs. activity), and the current status (waiting for exclusive access vs. exclusive access is granted but block hasn't been executed yet vs. block is executing).

This function is intended for debug purposes only. It is not declared in any headers, and its name and output are subject to change at any time.


New and Updated NSDocument Operations

In 10.8, NSDocument has added some new document management operations and has enhanced others.

Users can now move and rename documents from within the application by using the Move To… and Rename… commands from the File menu or the document titlebar menu. The Move To… command shows the user a simple panel that allows the user to move the document to a new directory. The Rename… command causes the title in the window titlebar to become editable, allowing the user to change the title of the document. The new APIs controlling these operations are -renameDocument:, -moveDocument:, -moveDocumentWithCompletionHandler:, and -moveToURL:completionHandler:.

The Duplicate command has also been enhanced. Immediately after the duplicate document is created, the window's title will become editable, allowing the user to customize the title. If the user specifies a custom title, then the document will be saved into the same directory as the original document, if possible.

Certain documents that the system decides should not be edited, such as attachments from the Mail application, will be automatically duplicated when the user edits them to avoid modifying the original. This works by immediately causing the document to be autosaved to the ~/Library/Autosave Information directory with NSAutosaveElsewhereOperation. The autosavedContentsFileURL is set to that location and the fileURL is set to nil, so the document starts behaving like an unnamed duplicate document.

There is new API to query and control the "locked" state of the document. -isLocked returns YES when NSDocument thinks its file cannot be edited for reasons including, but not limited to, the "user immutable" flag being set, insufficient permissions, and -checkAutosavingSafetyAndReturnError: returning NO. You can attempt to unlock the document with the -unlockDocumentWithCompletionHandler: and -unlockWithCompletionHandler: APIs. NSDocument will attempt to unlock the file by clearing the "user immutable" flag and restoring write permissions. If that is not sufficient to unlock the file, or the file cannot be unlocked, then the operation will fail. You can attempt to lock the document with the -lockDocumentWithCompletionHandler: and -lockWithCompletionHandler: APIs. NSDocument will attempt to lock the file by setting the "user immutable" flag. If the file cannot be locked, then the operation will fail. There are two separate IBAction methods for unlocking and locking: -unlockDocument: and -lockDocument:. If you provide custom UI for these menu items, at validation time you should use -isLocked to decide which action should be used.

For applications adopting +autosavesInPlace, the Revert command has been broken up into multiple menu items that allow reverting to key versions without requiring the user to enter the Versions browser. These menu items continue to use the -revertDocumentToSaved: action and use the menu item's tag to identify which item the user selects. You should not attempt to modify these menu items in any way.

Finally, -browseDocumentVersions: is a new IBAction method on NSDocument that triggers its entry into the Versions browser.


NSDocument Drafts

In applications linked on or after 10.8, when a user edits an Untitled document in an iCloud-enabled application, NSDocument will automatically save it to the default ubiquity container as defined by [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil], unless the user has specifically disabled this. In this case, the document will be saved to ~/Library/Autosave Information as normal.

Once saved to iCloud, these documents behave very much like regular saved documents—they have a proxy icon in the title bar, they can accumulate versions, and so forth. However, when the user chooses to Save or Close the document, a save panel will be presented to allow the user to confirm the automatically chosen name and location, assign a new one, or even delete the file. Documents in this state are called "drafts". If the user does something prior to Save or Close to indicate that they want the document to be kept around, the document will no longer be considered a draft and hence will not show the save panel on Save or Close. Moving, renaming, or locking the file or editing it in another application are some examples of what can cause a document to stop being a draft. You can get and set the draft status of a document with the new -[NSDocument isDraft] and -[NSDocument setDraft:] APIs.

When a newly created document is saved as a draft, NSDocument invokes -setFileURL: without affecting the "Edited" status of the document, as shown in the titlebar. None of the NSSaveOperations in Mac OS 10.7 allow for this, so NSDocument in 10.8 defines a new save operation: NSAutosaveAsOperation. This new NSSaveOperation will be used by -autosaveWithImplicitCancellability:completionHandler: under specific circumstances. For example, a new unsaved document that has been changed with NSChangeDone will use NSAutosaveAsOperation instead of NSAutosaveElsewhereOperation. The URL that is used for the NSAutosaveAsOperation is determined internally by NSDocument and attempts to avoid name conflicts by appending a number to the document's display name that will be incremented until no conflict is found.

Some applications use -updateChangeCount: to cause NSDocument to autosave changes that don't originate directly from the user. For example, when importing a non-native document type, some applications create a new document with the imported contents and call -updateChangeCount: to ensure that the document gets autosaved with those contents. Many applications use NSChangeDone for this purpose. However, since the user did not explicitly cause this change, it is undesirable to turn this document into a draft. Applications should be careful to use the correct NSDocumentChangeType—in this case, NSChangeReadOtherContents—to prevent the conversion into a draft. Using NSChangeDiscardable will also prevent the creation of a draft.

When a document is scheduled to become a draft, the effective autosaving delay is greatly reduced to ensure that an autosave happens very soon after the first change. Once NSDocument has completed the NSAutosaveAsOperation, or if the operation has failed without any expectation of succeeding in the future, that NSDocument instance will no longer use NSAutosaveAsOperation on future autosaves. A document that has failed an NSAutosaveAsOperation will revert to behaving like a traditional Untitled document and autosaving will use NSAutosaveElsewhereOperation until the user gives the document a location via the save panel.

If one or more your application's NSDocument subclasses should not save untitled documents as drafts, you should override +[NSDocument autosavesDrafts] and return NO.


NSDocument Customizing Default Draft Names

In Mac OS 10.7, all newly created documents were called "Untitled" or "Untitled <number>" until the user gave them a title by saving. In 10.8, NSDocument will allow your application to replace "Untitled" with a custom string that is more descriptive for your application. For example, a word processing app may choose to automatically name documents "Résumé" when they’re created from a certain template, or a spreadsheet application may prefer new documents to be called "Spreadsheet" instead of "Untitled". You can do this in your application by overriding -[NSDocument defaultDraftName] and returning your custom localized string. If necessary, NSDocument will append a number to make the name unique.


CoreAnimation updates for NSView (i.e.: CALayer backed NSView)

For applications linked on 10.8 and higher, the following changes are in effect:

• NSTextField has been updated to allow LCD font smoothing to work when the view is layer-backed. Prior to 10.8, NSTextField would directly draw the text into the layer's contents; this would cause text to render incorrectly due to the LCD font smoothing algorithm not having adjacent pixels to smooth fonts with. Layer-backed applications that manually draw text should move to using NSTextField to get proper LCD font smoothing. One caveat is that NSTextField does require an ancestor which is layer-backed and opaque; it does not have to be the direct parent view, but some view in the ancestor chain must be opaque for this to be turned on and work correctly.

• For applications that link on 10.8, all layer-backed views may turn off LCD font smoothing to have text render better. Specifically, if a view returns NO from -isOpaque, then AppKit will turn off LCD-font smoothing before calling the view's drawRect: implementation. Otherwise, the drawing of text into a transparent layer will look incorrect (generally, it looks bolder and not smooth). However, there may be some specific cases where a layer-backed view knows it is manually drawing text into an opaque area. For these views, it is recommended that font smoothing be explicitly turned back on before drawing text. An example:
CGContextRef ctx = NSGraphicsContext.currentContext.graphicsPort;
CGContextSetShouldSmoothFonts(ctx, true);
[@"Tandem Unicycle" drawInRect: ... ];
• Prior to 10.8, calling setLayer: on NSView may not have properly updated the layer's position until a resize or reposition of the view happened; this has been fixed.

• Prior to 10.8, an AppKit managed layer would be destroyed (and removed) when a view was removed from a window or moved to another parent view. This would have the undesired effect of losing any custom properties set on the layer. For any view that explicitly has setWantsLayer:YES, the underlying AppKit managed layer will not be destroyed, and custom set layer properties will not get lost.

• Prior to 10.8, when AppKit removed the layer it managed, it would leave the layer's delegate set to the NSView that had the layer. For applications linked on 10.8 and higher, the delegate will be set to nil when it is removed (only if it is "owned" by AppKit). An application must re-assign the delegate to the view, if they save off and restore an AppKit owned layer (in general, this isn't recommended, and to get a layer to stick around one should call setWantsLayer:YES).
• Prior to 10.8, an AppKit managed layer would always have the layerContentsRedrawPolicy set to NSViewLayerContentsRedrawDuringViewResize when the layer was (lazily) created by AppKit. This prevented the value from being set at an earlier time before the layer was created. In 10.8, this is now done at view initialization time (either in -init or -initWithCoder). For views that host custom layers (via a call to setLayer:), the layerContentsRedrawPolicy will still be set to NSViewLayerContentsRedrawNever when setLayer: is called; it is assumed that the client wants to own the layer and control when it redraws. For all other regular NSView backing layers, it is required to properly set the layerContentsRedrawPolicy (usually in initWithFrame: or initWithCoder:). Prior to 10.8, the layerContentsRedrawPolicy was encoded in the NIB along with other properties of the view, despite there being no way to set it in Interface Builder. On 10.8, the layerContentsRedrawPolicy is no longer encoded in the NIB and should be explicitly set in code.

• Prior to 10.8, a flipped view would explicitly control a layer's position by updating it every call to setFrameSize:. However, this conflicts with allowing CoreAnimation to do frame size animations on a background thread without input from AppKit. To solve this, AppKit now controls the -geometryFlipped on the backing CALayer. Prior to 10.8, the anchorPoint was also set to be either (0,0) or (0,1) -- it varied depending on the superview being isFlipped or not. On 10.8, the layer's frame is now equal to the view's frame. The anchorPoint is also always set to be (0,0), since the positions are now equal. In order to properly control the flipped state of a layer, override -isFlipped on NSView.

• There are now two ways to provide a layer's contents when a view is layer-backed. The new preferred way is to implement -wantsUpdateLayer and return YES. When this returns YES, a new method called -updateLayer will be called. At this point, it is appropriate to directly set the view.layer.contents to an image (NSImage or CGImageRef) which can properly stretch (i.e.: a 3 part or 9 part image). To indicate how it should stretch use the CALayer contentsCenter property. If additional UI is needed to represent a particular control, add subviews (or sublayers) in -layout. -layout will be called for views that respond YES to wantsUpdateLayer, even if auto layout is not used. To get a new call to -updateLayer, invalidate the view with a setNeedsDisplay:YES. To get a new call to -layout, call setNeedsLayout:YES. Utilizing wantsUpdateLayer can lead to better performance when a view is layer-backed. Most of the standard AppKit controls will implement this to return YES if drawing methods are not subclassed and overridden. If a view returns NO from -wantsUpdateLayer, then the layer's contents will be filled in with whatever is drawn in drawRect:.

• As of 10.7, the way layer-backed views animate frame changes varies depending on the value of layerContentsRedrawPolicy. Animations are typically initiated using the animator proxy (i.e.: [[view animator] setFrame:]). If the layerContentsRedrawPolicy is NSViewLayerContentsRedrawDuringViewResize, then AppKit assumes the view needs to redraw on each step of the animation, and it will drive the animation on the main thread by calling setFrame: multiple times. If the layerContentsRedrawPolicy is NSViewLayerContentsRedrawOnSetNeedsDisplay, then AppKit will utilize Core Animation to drive the animation, which is done implicitly on a background thread, and the view will not get a setFrame: call for each step of the animation. Instead, Core Animation will stretch the layer's contents based on how properties are set on the CALayer. Note that using NSViewLayerContentsRedrawOnSetNeedsDisplay makes the view work just like a CALayer would for the animation; this means any property changes (which animate) will instantly appear at their final state as soon as the animation call is made. In other words the following happens:
view.layerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicyOnSetNeedsDisplay; // This should be set in init
NSRect frame = view.frame; // Starts out as 100, 100
frame.size = NSMakeSize(300, 300);
[view.animator setFrame:frame]; // Animates the view frame from 100,100 to 300,300
// However, reading back in the view.frame at this point will indicate it is already at 300,300

• For 10.8 and higher, the default value for the layerContentsRedrawPolicy varies on a control-by-control basis inside of AppKit. For a plain NSView, the value will be NSViewLayerContentsRedrawOnSetNeedsDisplay. For a custom NSView that overrides drawRect:, the default value will be NSViewLayerContentsRedrawDuringViewResize. When using -wantsUpdateLayer, it is important to always set the layerContentsRedrawPolicy (ideally to NSViewLayerContentsRedrawOnSetNeedsDisplay).This will allow the view to animate frame changes with Core Animation, as opposed to AppKit driving the animation on the main thread.

• On 10.8, AppKit will control the following properties on a CALayer (both when "layer-hosted" or "layer-backed"): geometryFlipped, bounds, frame (implied), position, anchorPoint, transform, shadow*, hidden, filters, and compositingFilter. geometryFlipped is only changed for apps that link on 10.8 and higher. Use the appropriate NSView cover methods to change these properties.

• When a layer-backed view is invalidated with setNeedsDisplay: (or setNeedsDisplayInRect:) the window is no longer invalidated. This allows just the view that needs to redraw to be redrawn, and no others. However, applications need to take care that they didn't accidentally depend on side effect drawing that previously happened due to a parent view invalidating its children views.

• When a view had the layerContentsRedrawPolicy set to NSViewLayerContentsRedrawOnSetNeedsDisplay, the view (and layer) may still have accidentally been invalidated on frame changes. This has been fixed for applications linked against 10.8, and when NSViewLayerContentsRedrawOnSetNeedsDisplay is set, the application must explicitly call setNeedsDisplay: on frame changes (if required).

• NSAnimationContext now has a new property, allowsImplicitAnimation, for layer-backed views. The default value is NO, and it is automatically set to YES when the -animator proxy is used. When YES, it allows any CoreAnimation animatable property to be animated. This allows for nested animations. In other words, doing a [[view animator] setFrame:frame] will animate the frame on 'view', but also any subviews also. Typically this is desired, as it allows the autoresizing of subviews to be done animated, and all the animations to be tied together in the same animation block with the same duration. If a subview has some particular property they don't want to animate, a new animation group can easily be created to disable this behavior. The converse is also true; if you want a particular property to always have a CoreAnimation animation, then -allowsImplicitAnimation can explicitly be set to YES. An example use:
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
     context.allowsImplicitAnimations = YES; // Enable implicit CoreAnimation animations
     // Any operations done in this block will be animated
} completionHandler:nil];
The use of allowsImplicitAnimation is very similar to the existing properties in UIKit on iOS: [UIView areAnimationsEnabled] and [UIView setAnimationsEnabled:]

•NSView's -cacheDisplayInRect:toBitmapImageRep: will now work properly with layer-backed views. For applications linked against 10.8, the layer will be drawn using CALayer's renderInContext:, allowing it to render all sublayers, including ones that may not have an associated view. This allows the use of -wantsUpdateLayer and -updateLayer: to work with -cacheDisplayInRect:toBitmapImageRep:.

• When using layer-backed views, Core Animation will animate a layer from its presentation state to whatever state you set on the layer (or view). However, sometimes animating a layer-backed view may not animate from the desired location or state. This can happen if your view (and implicitly the layer) never had a chance to display. For instance, consider this example:
NSRect frame = view.frame; // Starts at 0,0 -- the view was already drawn on screen at this location
frame.origin = NSMakePoint(100, 100);
view.frame = frame; // The view should move to 100,100 -- however, it has not drawn yet
frame.origin = NSMakePoint(300, 300);
[[view animator] setFrame:frame]; // The view should animate from point 100,100 to point 300,300
The desired animation is from point 100,100 to 300,300 - however, what may happen is the view will animate from point 0,0 to 300,300! This is because changes to view and layer trees are coalesced inside of NSAnimationContexts/CATransactions. Because it is impossible to know the outermost scoping of an animation context / transaction, changes may be coalesced even when not expressly desired. To handle these cases, each set of changes/animations you want to be visible should be isolated in their own animation grouping. This will cause the view/layer to render with the requested property change. For instance, this will work to enforce the first rendering to happen before the animation starts by chaining the actual animation to the end of the first animation group:
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
context.duration = 0;
NSRect frame = view.frame; // Starts at 0,0 -- the view was already drawn on screen at this location
frame.origin = NSMakePoint(100, 100);
view.frame = frame; // The view should move to 100,100 -- however, it has not drawn yet
} completionHandler:^ {
NSRect frame = view.frame; // Now it has drawn at 100,100
frame.origin = NSMakePoint(300, 300);
[[view animator] setFrame:frame]; // This will correctly animate from 100,100 to 300, 300 using the default animation context duration
}];

NSTableView/NSOutlineView

For a View Based NSTableView (or NSOutlineView), it has always been incorrect to acquire a view from the table inside the delegate method tableView:heightOfRow: (or outlineView:heightOfItem:). Now, the table will detect if either of these methods is called from inside the delegate method implementation and throw an exception (or log an error): viewAtColumn:row:makeIfNecessary: and rowViewAtRow:makeIfNecessary:.

NSControl now has new API to show "expansion tooltips". This is primarily available for expansion tooltips to be shown when using a View Based NSTableView. Call setAllowsExpansionToolTips:YES to allow them to be shown.

NSTableView now has a method for registering (or associating) additional NIBs for a View Based NSTableView called -registerNib:forIdentifier:. When one calls -makeViewWithIdentifier:owner: the identifier, first the table will look in its reuse queue for a view to reuse with that same identifier. If one is not found, it will then look for registered NIBs with that identifier. If a NIB is found, it is instantiated with the 'owner' passed to the method. All top-level views in the instantiated NIB are then placed in the reuse queue with their current identifier. For this reason, it is important to always set the identifier for all top-level views in a NIB that is registered with the table. The particular view with the requested 'identifier' is then returned from -makeViewWithIdentifier:owner:. For a particular identifier, if there are no available views for reuse, or no associated/registered NIBs (or none created at design time in IB), then the method -makeViewWithIdentifier:owner: will return nil. A single NIB can be registered multiple times with different identifiers; this should be done for each top-level view that is in the NIB. A corresponding method, -registeredNibsByIdentifier, will return an NSDictionary with all registered NIBs. The key in the dictionary will be the identifier, and the value will be the NIB that has been registered. To unregister a NIB, pass 'nil' in for the NIB in -registerNib:forIdentifier:.

NSOutlineView

The following methods now support being animated via the -animator proxy: -expandItem:, -expandItem:expandChildren:, -collapseItem:, and -collapseItem:collapseChildren:. As an example, to animate the expansion of a particular item: [[outlineView animator] expandItem:item];

Prior to 10.8, calling -reloadItem: (or -reloadItem:reloadChildren:) on a NSView Based NSOutlineView may not have reloaded the disclosure triangle button if the row changed from being expandable to not being expandable (or vice-versa).


NSButton / NSButtonCell

For applications linked on 10.8, NSButton and NSButtonCell now use the Lion API drawFocusRingMask and focusRingMaskBounds to do its focus ring drawing. Previously, calling setShowsFirstResponder:YES on NSButtonCell and manually drawing the cell would include the focus ring. On 10.8 this is no longer the case, the cell no longer explicitly draws the focus ring. To customize the focus ring, override NSButtonCell's implementation of drawFocusRingMaskWithFrame:inView:.

An NSButton configured as a radio button (with the -buttonType set to NSRadioButton), will now operate in a radio button group for applications linked on 10.8 and later. To have the button work in a radio group, use the same -action for each NSButton instance, and have the same superview for each button. When these conditions are met, checking one button (by changing the -state to 1), will uncheck all other buttons (by setting their -state to 0).

NSInterfaceStyle

NSInterfaceStyle is now deprecated. The methods have not been used in AppKit in a while.

All the "mnemonic" set of methods are now deprecated. IE, in NSButtonCell: setTitleWithMnemonic:, setAlternateTitleWithMnemonic:, setAlternateMnemonicLocation:, alternateMnemonicLocation, and alternateMnemonic. The methods that take a title will still call setTitle: with the ampersand stripped from the parameter. Under MacOS, these methods have historically not been used and did nothing.


Zooming ScrollView

NSScrollView now has built-in magnification support. You must opt-in by setting the allowsMagnification property to YES. When the user performs a pinch gesture, NSScrollView will magnify, centering around the mouse location. When the user performs a smart zoom gesture (2-finger double tap on trackpads), NSScrollView will attempt to intelligently magnify the content under the cursor. However, NSScrollView needs help from your document view to determine your content layout. See the Smart Zoom section below for more details.
/* Allow the user to magnify the scrollview. */
@property BOOL allowsMagnification;
/* This value determines how much the content is currently scaled. To animate the magnification, use the object's animator.
The default value is 1.0.
*/
@property CGFloat magnification;
/* This value determines how large the content can be magnified. It must be greater than or equal to the minimum magnification.
The default value is 4.0.
*/
@property CGFloat maxMagnification;
/* This value determines how small the content can be magnified. The default value is 0.25.
*/
@property CGFloat minMagnification;
/* Magnify content view proportionally such that the entire rect (in content view space) fits centered in the scroll view.
The resulting magnification value is clipped to the minMagnification and maxMagnification values. To animate the magnification,
use the object's animator.
*/
- (void)magnifyToFitRect:(NSRect)rect;
/* Scale the content view such that the passed in point (in content view space) remains at the same screen location once the scaling
is completed. The resulting magnification value is clipped to the minMagnification and maxMagnification values. To animate the
magnification, use the object's animator.
*/
- (void)setMagnification:(CGFloat)magnification centeredAtPoint:(NSPoint)point;
The magnification property is observable. There are also notifications that will inform you when the magnification property is being changed due to user action. This may be due to the user performing a pinch gesture or a smart zoom gesture. When animating the magnification value yourself via the object's animator, these notifications are not sent.
/* This notification is sent at the beginning of a magnify gesture. The notification object is the scroll view performing the magnification.
*/
NSString *NSScrollViewWillStartLiveMagnifyNotification;
/* This notification is sent at the end of magnify gesture. The notification object is the scroll view view performing the magnification.
*/
NSString *NSScrollViewDidEndLiveMagnifyNotification;

Smart Magnification

There is a new NSEvent type for the smart zoom gesture (2-finger double tap on trackpads) along with a corresponding NSResponder method. In response to this event, you should intelligently magnify the content.
NSEventTypeSmartMagnify
- (void)smartMagnifyWithEvent:(NSEvent *)event;
NSEventTypeSmartMagnify is limited to 64 bit only.

Better yet, let NSScrollView perform the intelligence for you. In your NSScrollView document view, implement the following method to provide NSScrollView with semantic layout information of your content.
/* Return the complete rect of the most appropriate content grouping at the specified location. For example, if your content
is divided into three columns, return the entire rect of the column that contains the location. NSScrollView will attempt
to magnify such that the smaller dimension fits inside the scroll view while remaining within the
minMagnification, maxMagnification range.
   If your content layout is sub-divided further than one level deep (for example, two boxes that each contain multiple text
boxes), then use the visibleRect parameter to determine when to provide the rect of a sub-grouping. Always return a rect
for the appropriate grouping. If there is no deeper content grouping, return the rect for the deepest grouping. NSScrollView
will determine when to pan, magnify in, and magnify out.
   Return NSZeroRect for the default behavior.
*/
- (NSRect)rectForSmartMagnificationAtPoint:(NSPoint)location inRect:(NSRect)visibleRect;


Quick Look Gesture

There is now API to receive the Quick Look gesture (also known as the dictionary look up gesture). The user can perform this gesture with a three finger single tap, or the appropriate keyboard shortcut (Cmd-Ctl-D by default). There are two new NSResponder methods: an event method and an action method.
/* Perform a Quick Look on the content at location in the event. If there are no Quick Look items at the location, call super.
Also, see quickLookPreviewItems: further below.
*/
- (void)quickLookWithEvent:(NSEvent *)event;
/* Perform a Quick Look on the text cursor position, selection, or whatever is appropriate for your view. If there are no Quick Look
items, then call [[self nextResponder] tryToPerform:_cmd with:sender]; to pass the request up the responder chain. Eventually
AppKit will attempt to perform a dictionary look up. Also see quickLookWithEvent: above.
*/
- (void)quickLookPreviewItems:(id)sender;
To support the new event responder method, there is also a new NSEventType, NSEventTypeQuickLook. The only valid properties of and NSEventTypeQuickLook event are: -locationInWindow and -modifiers. A quick look event does not come in through the normal event mechanism, therefore there is no corresponding event mask for it, nor should you attempt to look for it in sendEvent: or with nextEventMatchingMask:… methods.

NOTE: NSApplication's default implementation of quickLookPreviewItems:, will perform a dictionary lookup. NOTE: There is a bug that causes the quickLoop responder methods to jump from NSWindow directly to NSApp bypassing NSWindowController, NSDocument, and NSAppDelegate.

NSPageController

NSPageController is a new class in 10.8 used for controlling swipe navigation and animations between views or view content.  It is useful for user interfaces which control multiple pages as in a book or a web browser history. NSPageController has a delegate that can be used to manage a predefined array of content via NSViewControllers, or used to manage a history of content snapshots built up due to user navigation.

NSPageController inherits from NSViewController. You must assign the view property to a view in your view hierarchy. NSPageController does not vend a view. NSPageController does insert itself into the responder chain.

Conceptually, NSPageController manages swiping between an array of pages (arrangedObjects). Using the selectedIndex, you can determine how many pages forward or backward the user may navigate.

There are two modes that NSPageController may operate in, History and Custom. The main difference between the two modes is that History mode expects pageController.view to be the content and Custom mode expects pageController.view to be be a container for the content that you will supply by returning viewControllers in your delegate methods.

NSPageController History Mode aka Non View Controller Mode

History mode is designed to be the easiest way to create a history UI. NSPageController will manage the history (arrangedObjects), snapshots and user navigation between pages in the history.

As the user navigates to new content, add to the history by calling navigateForwardToObject:. NSPageController will remove any arrangedObjects after the selectedIndex and then add object to the end of the arrangedObjects (and update the selectedIndex). Just like navigating in a new direction in a web browser, all forward history is lost once the user starts navigating a new path. After returning from navigateForwardToObject: you are free to update the contents of pageController.view.

During swiping, the following optional delegate methods are called in the following order:
- (void)pageControllerWillStartLiveTransition:(NSPageController *)pageController;
This is a good time to stash information that you need to restore, such a scroll positions. After returning from the above delegate method, pageController.view is hidden. In its place NSPageController shows a private view hierarchy to animate previously taken snapshots of the page history. This allows NSPageController to remain responsive to the user without any work on your part.
- (void)pageController:(NSPageController *)pageController didTransitionToObject:(id)object;
Called after a physically successful swipe, but before the animation has completed. The supplied object is the page the user navigated to -- the new selectedIndex object in arrangedObjects. If you need to start some background loading tasks, now is the time to do it, however, do not block the main thread or the animation will stutter or pause.
- (void)pageControllerDidEndLiveTransition:(NSPageController *)pageController;
The swipe and all animations are completed. Restore any scrolls setting or anything else you need to do. The pageController.view is still hidden at this point and you must call -completeTransition on NSPageController to tell NSPageController to hide the private transition view and show pageController.view. Often you do this immediately, however, if your content is not ready you can call this at a later date. See "Completing the Transition" below.

NSPageController Custom Mode aka View Controller Mode

Custom mode is designed to give you more control over the swiping process and to facilitate more UI designs than just history. You can even use custom mode to create a history UI. In this mode, pageController.view is a container view and the content views are vended by viewControllers supplied by your delegate. (Tip: Draw your background in this view.) To enable custom mode, you must implement the following two methods in your delegate:
- (NSString *)pageController:(NSPageController *)pageController identifierForObject:(id)object;
- (NSViewController *)pageController:(NSPageController *)pageController viewControllerForIdentifier:(NSString *)identifier;
NSPageController caches the view controllers supplied for each identifier and only asks its delegate to create more if one does not already exists in its cache (this is very similar to how view based NSTableViews work.) If you have different types of views you want to swipe in, then supply a different identifier for each type.

When needed, you will be asked to prepare a viewController with a page via the following optional delegate method. If you do not implement this method, then the representedObject of viewController is set to object.
- (void)pageController:(NSPageController *)pageController prepareViewController:(NSViewController *)viewController withObject:(id)object;
You will be asked to prepare a viewController with a nil object for each unique identifier it encounters. NSPageController will use this to generate a default snapshot for that identifier.

Generally, when using custom mode, the set of pages are known and it is your responsibility to set the arrangedObjects and initial selectedIndex.

During swiping, the following optional delegate methods are called int the following order:
- (void)pageControllerWillStartLiveTransition:(NSPageController *)pageController;
This is a good time to stash information that you need to restore, such a scroll positions. After returning from the above delegate method, NSPageController takes a snapshot of the selectedViewController.view and then removes it from pageController.view. NSPageController replaces it with a private view hierarchy to animate previously taken snapshots. Unlike when building up a history, snapshots may not yet exist for the page being navigated to. In this case, a previously gathered default snapshot is used for that page's identifier. Regardless if using a default snapshot, or a previously gathered snapshot of actual contents, a viewController is prepared for the page being navigated to. This viewController.view is then asked to draw on a background thread while swiping continues (note, the view is currently windowless). Once the background threaded drawing completes, the initial snapshot is replaced with the newly generated snapshot.
 - (void)pageController:(NSPageController *)pageController didTransitionToObject:(id)object;
Called after a physically successful swipe, but before the animation has completed. The supplied object is the page the user navigated to -- the new selectedIndex object in arrangedObjects. Important, the pageController.selectedViewController has not been updated yet. In custom mode, this delegate method isn't all that interesting, however, If you need to start some background loading tasks, now is the time to do it. Do not block the main thread or the animation will stutter or pause.
- (void)pageControllerDidEndLiveTransition:(NSPageController *)pageController;
The swipe and all swipe animations are completed. The selectedViewController.view is still detached at this point and you must call -completeTransition on NSPageController to tell NSPageController to hide the private transition view and update the selectedViewController. Often you do this immediately, however, if your content is not ready you can call this at a later date. See "Completing the Transition" below.

NSPageController Completing the Transition

As discussed above, NSPageController uses a private view hierarchy during swiping. To create a seamless transition to the new content, it is your responsibility to inform NSPageController when you are ready to draw the new content. Ideally, the new content should match the snapshot and the user is none the wiser. You tell NSPageController to complete the transition by calling -completeTransition. If needed, a viewController is prepared and then the contentView is shown (or added) to the view hierarchy and the private transition view is hidden.

During NSPageController initiated animations, -pageControllerWillStartLiveTransition and -pageControllerDidEndLiveTransition are called on the delegate. Generally during pageControllerDidEndLiveTransition you will call -completeTransition. Programatic animations via the animator proxy do not call the delegate methods and you are responsible for calling -completeTransition when the animation completes.This is easily done via a completion handler on an NSAnimationContext grouping. (see below)

To instantly change the selectedIndex:
  pageController.selectedIndex = newIndex;
To animate a selectedIndex change:
  [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
[[pageController animator] setSelectedIndex:newIndex];
} completionHandler:^{
[pageController completeTransition];
}];

NSPageController Transition Styles

There are three transition animation styles. These transition styles are independent of the delegate mode. It is perfectly reasonable to create a history style UI using the viewController (custom mode) delegate methods. Simply set the transition style appropriately.

NSPageControllerTransitionStyleStackHistory - Pages are stacked on top of each other. Pages animate out to the right to reveal the previous page. Next pages animate in from the right. (See Safari as an example)

NSPageControllerTransitionStyleStackBook - Pages are stacked on top of each other. Pages animate out to the left to reveal the next page. Previous pages animate in from the left. (See Preview as an example)

NSPageControllerTransitionStyleHorizontalStrip - Pages are laid out next to each other in one long horizontal strip

The best way to think about the two stack transition styles is to think about the way the pages are stacked on top of each other. In a Book, page 1 is first. Page 2 and subsequent pages are stacked underneath page one. When navigating forward, the user swipes the current page out to reveal the next page. When navigating backward, the user swipes the previous page in and on top of the current page. In History, the pages are stacked over time in reverse order. That is, page 2 is stacked on top of page 1 and page 3 is stacked on top of page 2, etc… When navigating backward, the user swipes the current page out to reveal the previous page. When navigating forward, the user swipes the next page in and on top of the current page.

NSPageController Layer Backed Mode

When using the Custom mode, if pageController.view is layer backed, live layers are used during transition instead of snapshots.

NSPageController Notes

NSTableView is not thread safe! Do not tell NSTableView to reload its data while it is drawing on a second thread or it will crash. When using history mode, do not wire pageController.view to an NSSplitView subview. This will actually cause a 3rd split when the private transition view is put in the view hierarchy. You can work around this by using an empty NSView as the NSSplitView subview and placing the real contents in a subview of the empty view.


Smooth Scrolling

Smooth scrolling has been removed from user preferences. A consequence of this is that the default name has changed. Any use of @"AppleScrollAnimationEnabled" should be replaced with @"NSScrollAnimationEnabled". If you need to determine the default state of smooth scrolling, the following code will return the correct BOOL value
  [[NSUserDefaults standardUserDefaults] boolForKey:@"NSScrollAnimationEnabled"];

Accelerated Scrolling

Similar to iOS, on the third consecutive fast scroll gesture, the scrollingDelta of the scrollWheel event is automatically accelerated until either the user takes too long between physical scrollWheel gestures or the user starts to scroll slowly during another accelerated scrollWheel gesture.


Changes in Loading Nib Files

To support new features in localization, some nib loading paths in AppKit no longer use the deprecated loadNibFile:externalNameTable:withZone: method. If your application uses certain alternative localization techniques that depend on this method being called, and is linked with the Mountain Lion SDK or later, then localized resources may not be loaded correctly. You should switch to the new localization features that are part of Mountain Lion.


Auto Layout View Priorities

In 10.8, the NSView methods setContentHuggingPriority:forOrientation: and setContentCompressionResistancePriority:forOrientation: now raise an exception if the priority is zero or less, or more than NSLayoutPriorityRequired. In 10.7 and earlier, these values were silently accepted but could’ve later led to a crash.

Auto Layout NSSplitView improvements

In 10.8, NSSplitView properly respects constraints applied to its subviews, such as their minimum view widths. There are also new APIs for controlling the holding priorities, which determine both the NSLayoutPriority at which a split view holds its sizes and also which views change size if the split view itself grows or shrinks.
- (NSLayoutPriority)holdingPriorityForSubviewAtIndex:(NSInteger)subviewIndex;
- (void)setHoldingPriority:(NSLayoutPriority)priority forSubviewAtIndex:(NSInteger)subviewIndex;
In order to take advantage of these improvements, you must NOT implement any of the following NSSplitViewDelegate methods:
splitView:constrainMinCoordinate:ofSubviewAt:
splitView:constrainMaxCoordinate:ofSubviewAt:
splitView:resizeSubviewsWithOldSize:
splitView:shouldAdjustSizeOfSubview:
These methods are incompatible with auto layout. You can typically achieve their effects and more with auto layout.

Auto Layout NSTextField wrapping improvements

In 10.8, NSTextField has some new APIs to allow better support for wrapping text fields under auto layout.
- (void)setPreferredMaxLayoutWidth:(CGFloat)width;
- (CGFloat)preferredMaxLayoutWidth;
When you ask a wrapping text field for its size, by default it lays out as if it has infinite width available, i.e. in one long line (assuming it has no line break characters). Its intrinsicContentSize is the same: wide and short. However, if you set a preferred maximum layout width, the text field then measures itself as if it were confined to a rect of that width (and infinite height). Under auto layout, assuming no other constraints determine its size, its width will not exceed its preferred max, and its height will be sufficient to show all the text contents.

A common pattern is to have a wrapping NSTextField whose width is some constant determined by other constraints, and whose height should be sufficient to show the full text at that width. That can be achieved with the following pattern:
[[textField window] layoutIfNeeded];
[textField setPreferredMaxLayoutWidth:[textField alignmentRectForFrame:[textField frame]].width];
This works as long as the text field view width is not dynamic.

Auto Layout NSControl alignment rects

In Lion, the alignment rects, baselines, and intrinsic content sizes reported by many controls were slightly off. In 10.8, these have been corrected. In particular, NSPopUpButton has been modified to report an intrinsicContentSize with significantly less extra padding.

AppKit has historically resisted changing a control's reported cellSize for binary compatibility reasons, even if the underlying artwork changes. The intrinsicContentSize is intended to always be correct, and can be used as a "better sizeToFit" even when not using auto layout, like so:
  NSRect alignmentFrame = (NSRect){NSZeroPoint, [control intrinsicContentSize]};
[control setFrame:[control frameForAlignmentRect:alignmentFrame]];

Be aware that this is only sensible for controls that have both a natural width and height, like NSButtons. Controls that are fully flexible (such as NSSlider) will report NSViewNoIntrinsicMetric for their width and/or height, and you should set those dimensions explicitly.

Auto Layout and Non-Finite Frames

Under auto layout in 10.7, if a view returns YES from translatesAutoresizingMaskToConstraints and that view has a non-finite frame size or origin (such as infinity or NaN), an exception would be raised when creating the corresponding constraints. When not using auto layout, the frame has historically been silently tolerated (though the view would not appear). In 10.8, auto layout now logs a warning and flushes all non-finite frames to zero, for better compatibility with the non-auto layout behavior.

Of course, all non-finite view frames are bugs. To assist in tracking these down, a new user default NSViewRaiseOnInvalidFrames is provided. If this is set to YES, then both setFrameSize: and setFrameOrigin: (and by extension, setFrameSize:) will raise an exception if their parameters are non-finite.


NSSharingService

NSSharingService is a new class in 10.8 that can be used to share items to different kinds of local and remote services. Items are objects which respond to the NSPasteboardWriting protocol, like NSURL, NSImage or NSString. Please refer to the interface in <AppKit/NSSharingService.h> for the API.

If an NSURL is a file URL (pointing to a video for example), then the content of the file will be shared. If the URL is remote, then the URL itself will be shared.


Sharing service integration for NSTextView

The default NSTextView contextual menu contains sharing service items relevant for the current selection.

In addition to the contextual menu support, -[NSTextView orderFrontSharingServicePicker:] action method provides support for the sharing service picker facility provided by NSSharingService. A new NSTextViewDelegate method, -textView:willShowSharingServicePicker:forItems:, can be implemented by the delegate to further customize the picker behavior using NSSharingServicePicker.


ARC Weak References

Starting in 10.8, instances of NSWindow, NSWindowController, and NSViewController can be pointed to by ARC weak references.


NSApplication

If an application is launched because a user selected a notification in the Notification Center, NSApplicationLaunchUserNotificationKey will be present in the userInfo dictionary of NSApplicationDidFinishLaunchingNotification. Its value is an NSUserNotification object.
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
NSUserNotification *launchNotification = [[notification userInfo]
objectForKey:NSApplicationLaunchUserNotificationKey];
if (launchNotification) {
// application was launched by a user selection from Notification Center
}
}
NSApplicationLaunchUserNotificationKey has replaced NSApplicationRemoteNotificationKey, which was introduced in Lion but is deprecated in Mountain Lion.

Full Screen

We now allow a fullscreen window to occupy an external display. This allows users to specify which display should contain the fullscreen window by first moving the non-fullscreen window to the desired display. When a fullscreen window is on an external display, other displays are covered in linen shield windows, as before. The menu bar can be shown by mousing up to the top of the external display. The Dock is autohidden, and remains on whatever display edge is specified in user preferences. If your application implements a custom fullscreen transition, using window:startCustomAnimationToEnterFullScreenWithDuration:, you should choose the destination screen for the fullscreen window by finding the screen containing the majority of the window prior to the transition.

Much of the underlying Spaces architecture has changed in 10.8. This should have no effect on your application if you are using the NSWorkspace and NSWindow API, but you may notice changes if you have assumptions about timing of when the current space changes during a fullscreen transition, for example.


Using NSSavePanel / NSOpenPanel API in an App Sandbox

When you enable app sandboxing for your application (by checking "Enable App Sandboxing" for a target in Xcode), any calls to NSSavePanel and NSOpenPanel objects are redirected to a separate process which displays the Save/Open panel. This process is pboxd (aka "Powerbox").

Sandboxed NSSavePanel and NSOpenPanels were introduced in Lion. There are no new API changes in Mountain Lion, however the internals were worked on extensively to add support for iCloud and to resolve various usage and performance issues. The notes here are tips for developer usage.

A Note on Deprecated APIs:

Subtle aspects of deprecated methods in NSSavePanel and NSOpenPanel will not work when your app is sandboxed. Replacement methods have been available for a while, Changing your code to use the supported APIs will not prevent you from disabling the app sandboxing in the future. Now would be a good time to heed the warnings the compiler has been giving you.

Class Hierarchy:

As described in : The App Sandbox Design Guide

The declared (compile-time) class hierarchy for NSOpenPanel and NSSavePanel appears the same for sandboxed and non-sandboxed applications, but the actual (run-time) class hierarchy changes. Early versions of the App Sandbox Design Guide documentation were incorrect. Here is a (correct) recap:

The declared hierarchy looks like this:
NSOpenPanel : NSSavePanel : NSPanel : NSWindow : NSResponder : NSObject
The actual (run-time) hierarchy looks like this:
NSOpenPanel : NSSavePanel : NSObject
if you or anyone to whom you pass an instance of an NSOpenPanel or NSSavePanel assumes that the methods of NSPanel, NSWindow, or NSResponder are available through that instance — your app may encounter a method-not-found exception.

Availability of NSWindow APIs on an instance of NSOpenPanel and NSSavePanel:

In Mountain Lion, in a sandboxed app, you can treat an instance of NSSavePanel or NSOpenPanel as if it were subclassed from NSPanel during three well-defined spans of time: Delegate method calls, panel completion blocks, and accessory view action method calls.

Restricted File Access affects Delegate Method support:

As described in the "Powerbox and File System Access Outside of Your Container" section of the The App Sandbox Design Guide, a sandboxed app has restricted access to the file system unless and until the user specifies otherwise on a file-by-file basis, or your application has extra entitlements to files. The NSOpenPanel and NSSavePanel delegate methods behave the same under App Sandboxing, however what you can do with the URLs supplied by those methods has changed. The URLs passed to these delegate methods cannot be used to obtain information about the objects to which the URLs refer. This means not only that file contents are inaccessible but also object meta-data is inaccessible. In other words, about all you can do with these URLs is analyze them as (standardized, structured) strings.

NSOpenPanel and NSSavePanel are not intended for use within a Sandboxed Application's container directory. The Application container directory is an abstraction which an end user is unlikely to be able to find with Finder. Therefore an Application container directory should not be presented to an end user in the open and save panels either. If your application attempts to set the initial directory of an open or save panel to the Application container directory (or a sub-directory therein), the code in pboxd detects this and redirects the panel to the user's home directory.

Titlebar Renaming

There is no public API for Titlebar Renaming outside of NSDocument. You may note that even if your application is not app sandboxed, an instance of pboxd (aka "Powerbox") is running while a Titlebar Renaming session is in progress. Titlebar Renaming uses pboxd even in non-sandboxed applications.


Changes to Resume for Applications

In order to improve system startup performance, applications which were hidden at time of logout will by default only be partially launched when resuming after a reboot. Such partially relaunched applications use much less system resources. When the user activates an application launched this way, it will be fully restored and behave normally.

If this behavior is undesirable for your application (for example, a mail application may be checking for mail and displaying a count of unread messages in its dock icon even if the user isn't interacting with it), you can use the Automatic Termination APIs to provide information to the system about what your app is doing, allowing it to make more appropriate choices. If an automatic-termination-aware application disables automatic termination via the -[NSProcessInfo disableAutomaticTermination:] API, the OS will assume that it's in the middle of something that should be resumed, and will fully relaunch it on restart. Once automatic termination is reenabled via -[NSProcessInfo enableAutomaticTermination:], the OS will resume deciding between full, partial, or no relaunch to minimize startup time without violating the user's expectations.

Adopt Automatic Termination

Automatic Termination is a facility introduced in OS X Lion. It allows underlying processes to be terminated by the system automatically, independent of the running state of the application itself. We intend to rely on Automatic Termination even more in the future, and encourage you to adopt it in your applications. You can do this by opt'ing into Automatic Termination via the Info.plist entry NSSupportsAutomaticTermination (or calling -[NSProcessInfo setAutomaticTerminationSupportEnabled:YES] early on), and then calling -[NSProcessInfo disableAutomaticTermination:] and -[NSProcessInfo enableAutomaticTermination:] as needed.


NSTextAlternatives

NSTextAlternatives is a new immutable value class that stores a list of alternatives for a piece of text and communicates selection of an alternative via a notification. NSTextAlternatives instances are attached to attributed strings as the value of a new attribute, NSTextAlternativesAttributeName.

In 10.8 the use case for NSTextAlternatives is dictation, but this class is not strictly tied to dictation and may be used for other purposes in future releases.

The class has two attributes:  primaryString (representing the text that was actually chosen and used in the input string), and alternativeStrings (representing the alternative possible interpretations that the user might select instead).  These are separate because the text system needs to deal with them separately, using the primaryString to make sure that the text is still in the same state as when it was entered, and presenting the alternativeStrings via UI similar to that currently used for correction alternatives.

When the user picks one of the alternative strings, the text view calls -noteSelectedAlternativeString: on the NSTextAlternatives object.  Subclasses of NSTextAlternatives may do what they like in this method, but the base class implementation sends a notification NSTextAlternativesSelectedAlternativeStringNotification, with the selected alternative string in the user info under the key @"NSAlternativeString". This way arbitrary objects can listen for user selections of alternative strings.


Additional API for Spellchecking

There is an additional method on NSSpellChecker:
- (NSString *)languageForWordRange:(NSRange)range
inString:(NSString *)string
orthography:(NSOrthography *)orthography;
Clients who have an NSOrthography from NSTextCheckingTypeOrthography checking and wish to determine a specific language from it for a particular word, for example to pass in to -guessesForWordRange:inString:language:inSpellDocumentWithTag:, -correctionForWordRange:inString:language:inSpellDocumentWithTag:, or -completionsForPartialWordRange:inString:language:inSpellDocumentWithTag:, should use this method to obtain it. This method is publicly documented in 10.8 but is available back to 10.7.


NSImage

In 10.8 we've added API to NSImage and NSCustomImageRep allowing clients to delegate drawing to a block:
+[NSImage imageWithSize:flipped:drawingHandler:]
-[NSCustomImageRep initWithSize:flipped:drawingHandler:]
-[NSCustomImageRep drawingHandler]
These APIs make it easy to create an image (or custom image rep) that delegates its drawing to a block. This block is invoked at draw time, allowing drawing to be tweaked as appropriate for the destination context pixel density, color space, and other properties. This API can replace many (but not all) existing uses of lockFocus/unlockFocus. The existing lockFocus implementation performs all drawing against a single bitmap representation. This causes problems when images are moved between displays of different pixel densities (and to a lesser extent, different colorspaces).

Like other non-bitmap image rep types, drawing is cached as appropriate for the destination context. Practically speaking, the drawingHandler block will be invoked the first time the image is drawn to a particular type of destination (1x or 2x screen, for example). Subsequent drawing operations to the same type of destination will reuse the previously generated bitmap.

When drawing, NSImage has always tried to use a representation with at least as many pixels as the destination rectangle. Many apps try to implement banners and 3 part / 9 part images by stretching an NSImage over a much larger area (usually only on a single axis). With the addition of 2x assets these apps are finding this policy displays the 2x image rep when they would prefer the 1x rep. This behavior can be changed by using the new matchesOnlyOnBestFittingAxis property on NSImage. It is still preferable to use NSDrawThreePartImage and NSDrawNinePartImage, when possible.

Since SnowLeopard it has been possible to use NSImage as the contents of a CALayer. With the recent proliferation of 2x assets, this technique is increasingly being used to simplify HIDPI adoption.  This technique does however face certain limitations:

• The contentsGravity of the layer must be kCAGravityResize, kCAGravityResizeAspect, or kCAGravityResizeAspectFill. For all other contentsGravities behavior is undefined.
• When rasterizing a resolution independent representation, or selecting from multiple representations, only the backingScaleFactor of the view hosting the layer is used. This means that any scales introduced by modifying the bounds or transform of the layer or its ancestors are ignored.

In 10.8, NSImage now offers two new methods to more explicitly deal with a layer's contentsScale. These methods are -recommendedLayerContentsScale: and layerContentsForContentsScale:. These methods can be used to account for scales present in the layer tree (for example due to the layer bounds, or a layer transform). They also work for all contentsGravities.
static void updateLayerWithImageInWindow(NSImage *image, CALayer *layer, NSWindow *window)
{
    CGFloat baseScaleFactor = [window backingScaleFactor]; // This is the scale factor of the screen we are displayed on.
    NSSize imageSize = [image size];
    CGRect layerSize = [layer bounds].size;
    CGFloat additionalLayerScaleFactor = fmax(layerSize.width / imageSize.width, layerSize.height / imageSize.height);
    CGFloat desiredScaleFactor = baseScaleFactor * additionalLayerScaleFactor; // this scale factor is appropriate
     // for the actual pixel bounds of the layer.
    CGFloat actualScaleFactor = [image recommendedLayerContentsScale: desiredScaleFactor]; // Don't use a higher scale
     // factor if the image can't provide it. If the image is resolution independent
     // the return value will be the same as the input.
    id layerContents = [image layerContentsForContentsScale:actualScaleFactor]; // Now we have an appropriately
     // sized object to use as the contents of a layer.
    [layer setContents:layerContents];
    [layer setContentsScale:actualScaleFactor];
}

NSWindow

As of 10.7.3, AppKit sends NSWindowDidChangeBackingPropertiesNotification when a window's backingScaleFactor and/or colorSpace changes. When running on a system version where this new notification is available, applications should use it instead of NSWindowDidChangeScreenProfileNotification to watch for changes to either of these backing store properties. There is also a corresponding delegate method.
NSString *NSWindowDidChangeBackingPropertiesNotification;
@protocol NSWindowDelegate <NSObject>
@optional
...
- (void)windowDidChangeBackingProperties:(NSNotification *)notification;
...
@end
The userInfo dictionary contains two keys: NSBackingPropertyOldScaleFactorKey has an NSNumber value that specifies the window's previous backingScaleFactor, and NSBackingPropertyOldColorSpaceKey has an NSColorSpace value that specifies the window's previous colorSpace . You can compare these with the backingScaleFactor and colorSpace at the time of the notification, to determine which of these two properties changed. Note it is possible for both to have changed.
NSString *NSBackingPropertyOldScaleFactorKey;
NSString *NSBackingPropertyOldColorSpaceKey;

NSView

NSView has a new override point: -viewDidChangeBackingProperties. This method provides a simple override point from which a client may apply changes to their layer hierarchy. It will be invoked when the view is added to a window, or when that window changes colorspace or backing scale factor. This method may be overridden to apply the current contentsScale to their layer tree.

Additionally, we have introduced an optional method for CALayer delegates:
- (BOOL)layer:(CALayer *)layer shouldInheritContentsScale:(CGFloat)newScale fromWindow:(NSWindow *)window;
When implemented, NSView will invoke this method on a layer's delegate when the view is added to the window, or the window's resolution changes. NSView does this by enumerating the layer tree attached to it and inspecting each layer delegate in turn. Note that when a layer is added to an already visible layer tree this method will *not* be invoked. If you return YES from this method, NSView will set the layer's contentScale to match the backingScaleFactor of the window it is hosted in; and mark the layer dirty using -setNeedsDisplay.

Managing NSImages with multiple representations

Taking advantage of NSImage's multiple representation capability is important for high resolution support in your apps. NSImage has facility to choose and load the appropriate representation at runtime, depending on the context in which it is being drawn. It will also reload additional representations as needed when asked to draw into different contexts.

Although NSImages with multiple representations can be created at runtime, by calling addRepresentation:, it's often much easier to load such images from files. A call such as [NSImage imageNamed:@"foo"] will create an NSImage backed with all image files named "foo" in your app bundle, for instance foo.png, foo.tiff, foo.pdf, etc. In addition, the tiff file format can contain multiple representations within a single file, eliminating the need to have multiple files. This facility has been in place since OS X 10.0.

When multiple representations are providing for a single image, it's very important that the representations all have the same intrinsic size (as returned by -size). For bitmap image files with different pixel counts this is achieved by setting the density of the image properly. Since the default density of images is 72dpi, setting the density of 2x files to 144dpi achieves this constraint. When creating artwork this is often done by specifying a resolution value in an image sizing panel; programmatically this is done by setting the size of the NSBitmapImageRep explicitly to something other than {pixelsWide, pixelsHigh}.

Starting in 10.7, NSImage added support for the iOS naming convention for high resolution images, which means [NSImage imageNamed:@"foo"] will also pick up foo@2x.png. In such cases the pixel dimensions of the 2x image need to be 2x, and NSImage will assume that the density is twice that of the 1x file.

For artwork coming from bundles other than the app bundle, the 10.7 method -[NSBundle imageForResource:] can be used to do the same combination of individual files.

Despite this multi-file support in NSImage, we don't really expect you to use it much. If you have resources foo.png and foo@2x.png in your project resources, Xcode by default is going to roll them together into a multi-representation foo.tiff that contains both during build. We recommend this approach as a way to reduce the number of files in your shipping app bundles.

Command line tool tiffutil can be used to manually combine individual bitmap image files into single tiff files.

Managing application and document icons

Xcode 4.4 provides support for combining application and document icons, which use the .icns image file format. In your project resources you provide "iconset" folders that contain the individual files which will be combined at build time into .icns files. The format for the iconset folder is described in the document "High Resolution Guidelines for OS X."

Command line tool iconutil can be used to manually combine individual bitmap files into single icns files.

Note that support for icns files with high resolution representations extends back to OS X 10.6, but not 10.5.

NSOpenGL

The NSOpenGLContext methods -setFullScreen and -setOffScreen:width:height:rowbytes: no longer do anything. This is because the functions on which they are are based (CGLSetFullscreen and CGLSetOffScreen) no longer work. Check the documentation for CGLSetFullscreen and CGLSetOffScreen for replacement functionality.


NSColor

There's a new NSColor class method to return the lighter linen color that should be used for backgrounds of pages and revealed view areas:
+ (NSColor *)underPageBackgroundColor;
There are two new NSColor methods to convert back and forth from CGColorRefs:
+ (NSColor *)colorWithCGColor:(CGColorRef)cgColor;
- (CGColorRef)CGColor;
These methods do not guarantee round-trip fidelity. -colorWithCGColor: may return nil in some cases (for instance, it's not implemented for indexed color spaces). -CGColor will never return nil, but the result may be an approximation.

Conversion of colors with -[NSColor colorUsingColorSpace:] using arbitrary spaces has been speeded up greatly to match the speed of conversion using the built-in standard color spaces.


NSProgressIndicator

The bar-style progress indicator now supports progress animation in right-to-left configuration when -[NSApplication userInterfaceLayoutDirection] returns NSUserInterfaceLayoutDirectionRightToLeft.


NSRulerView

The icon for right and left tab markers are correctly rendered in the vertical text orientation.


New gestures for NSTextView

NSTextView supports the Quick Look gesture by implementing new NSResponder APIs, -quickLookPreviewItems: and -quickLookWithEvent:. Also, the smart magnify gesture is supported through -rectForSmartMagnificationAtPoint:inRect:.


NSFont

The default fixed pitch font in Mountain Lion is Menlo 11pt. +[NSFont userFixedPitchFontOfSize:] with 0.0 point size now returns Menlo 11 instead of Monaco 10.

Starting from this release, the default use of screen fonts is discontinued. The text rendering and measurement APIs for user interface elements such as NSStringDrawing and NSCell methods no longer substitute font attributes with their screen font counterparts automatically. The default setting for -[NSLayoutManager usesScreenFonts] is now NO for applications linked on this and later releases. You can keep your applications running with Lion-behavior by setting a new NSUserDefaults key, NSFontDefaultScreenFontSubstitutionEnabled. NSFontDefaultScreenFontSubstitutionEnabled controls the overall default screen font substitution behavior. When set to YES, the screen font substitution is performed by all text APIs just as on previous releases. The default value is NO.

Applications can store the screen font setting into documents via NSUsesScreenFontsDocumentAttribute.