As Cocoa developers, whenever we get a major new release of Mac OS X, we have to spend time familiarising ourselves with the new APIs and facilities on offer. One of the main goals of this investigative process is to identify controls and funtionality which we previously had to implement ourselves, but which are now provided natively for us.
I’ve been using Leopard for the last few months, and I thought I’d post a partial list of new and improved APIs which may be of interest to Cocoa application developers. I’m going to classify these in terms of what you can do with them, rather than by class-name or other such relatively obscure aspect, and I’ll include some screenshots where appropriate. Please feel free to add your own observations via the comments. I’ll stick roughly to the order used in the AppKit and Foundation release notes, which you should also read if you’re serious about getting the skinny on what’s new in Leopard.
Naturally, backwards-compatibility does complicate matters somewhat, but that doesn’t detract from the usefulness of getting a quick high-level overview of the new toys we now have to play with.
Update: Added some new screenshots and clarifications, and mention of a couple of the new frameworks available. Oh, and welcome to all Daring Fireball readers – I knew it was taking longer than usual to pull down my server logs. ;)
This one needs little introduction. Spend some time with the documentation, paying particular attention to the concept of layer-backed views and the animator proxy. You can do some incredible things simply by setting up properties in Interface Builder, and can usually get a very convincing animation simply by sending a message to [yourView animator] instead of just to yourView.
Take a look at NSAnimatablePropertyContainer to add your own animatable properties to views too.
(Note: both of these examples, “Covert” Flow and Cocoa Slides, are part of the Core Animation Coding Headstart sample code. I believe it’s still just available to those with access to the Leopard seeds, but hopefully/presumably it’ll become publicly available soon.)
You’re now notified (via methods you can override in a subclass) when a view is hidden, unhidden, or is about to draw. This will help you do more efficient pre-calculations and caching for your drawing code. You can also now directly manipulate all of a view’s subviews at once.
Working with Quick Look
You can create Quick Look Plugins which allow Quick Look to preview the content of your app’s custom documents, in the same way as Tiger allowed you to add Spotlight Plugins to allow indexing those documents.
You can also request a Quick Look-generated preview of a document using QLThumbnailImageCreate() from the QuickLook framework (thanks to Mek for pointing that out). The preview can be of an arbitrary size you specify, of any document you like, and you can even tell the framework to draw it as an “icon” (i.e. with a drop-shadow, document page-curl and so on).
Managing multiple views (for custom tab controls, or such)
There’s a new NSViewController class that lets you manage a set of views, and supports bindings. It might eliminate a lot of glue code to swap views in response to user interaction.
iPhoto-like animating grid of images or views
You get this for free with IKImageBrowserView. Try setting one up in Interface Builder and run the simulation; it’ll work right then and there. The example shown below (and the default behaviour of the control in Interface Builder) is a zero-code, nib-only view of your desktop pictures, supporting multiple selection, automatic re-tiling and animated drag-reordering.
Note that IKImageBrowserView is a pre-made control using the new NSCollectionView class; see its documentation for more details (it used to be called NSGridView in earlier seeds, but that name has been changed to NSCollectionView). There’s also a sample app for the new PubSub framework which uses IKImageBrowserView; you can find it in /Developer/Examples/PubSub/NewMusic/ (thanks to Jens Alfke for the note).
Setting up your own Smart Groups/Playlists/Folders
You can use the NSRuleEditor and NSPredicateEditor classes to get the familiar rule-editing interface for your app.
Putting custom views in menus
NSMenuItem now has a -setView (and a -view) method, to put arbitrary views in your menus without resorting to Carbon. Animation via timers will work too, but pay attention to the runloop you use (it has to be the event-tracking runloop mode, since it’s in a menu).
You’ll now be notified (via delegate methods) when a menu-item is opened, closed, highlighted and unhighlighted – this is very handy for custom view menu-items, but applies to all items.
You can now have the same keyboard shortcut in multiple menus as long as the action of all items with that shortcut is the same (good for contextual menus duplicating commands in the menubar), and (significantly) if a shortcut would trigger a disabled item, your app now gets the chance to handle that shortcut anyway. This could remove the need for some trivial NSApplication subclasses.
The Print panel is much improved, particularly in terms of accessory view support; your app can really get in there and customize what’s shown. If printing is a significant part of your app’s functionality, you need to take a fresh look at NSPrintPanel and NSPageLayout – there’s a huge amount of new material and functionality there.
Uniform Type Identifiers
Leopard now richly supports using UTIs throughout the document architecture, including NSDocument, open/save panels, bundle info, NSWorkspace and so on. Ditto for drag-types, pasteboard data, services definitions, image types, and a host of others. If you’re looking to simplify and unify how your app classifies data types without using lots of arbitrary constants, take a look.
Get splitviews like those in Mail etc
NSSplitView has been significantly enhanced; read through the API and you’ll see that it’s much better about programmatic collapsing, changing divider thickness and active area, and even specifying an external area which acts as a proxy draggable zone to move the splitter (just like the little thumb in Mail and many other apps). There are also bug fixes in there for things like the long-standing progressive rounding errors when resizing.
(And if it’s still not up to scratch, you can of course continue to use RBSplitView.)
Putting document icons in the titlebar
You don’t need to be using the NSDocument architecture for this; there are new methods to control the icon, what it represents, whether the popup menu appears, and so on.
HUD windows, like in iPhoto’s palettes
There’s now a HUD Window type, which is an NSPanel. It can even be borderless, and still get the transparent black background and so on. This might let you get rid of custom window subclasses (like some of mine, for example).
Controlling the texture/metal on your windows, and where it draws
There are now methods to determine the “border thickness” of the texture on your windows; you can say that, for example, there should be texture on the bottom 100 pixels or such. This can remove the need for custom window subclasses, or superfluous views which only draw a background.
Integrating with Spaces
Your windows can choose what happens when they are made visible on a certain Space, and when the user switches Spaces. Basically, you can choose whether it uses the default behaviour (appears on one space, stay there unless moved explicitly), or always appears on the active space, or appears on all spaces. See NSWindowCollectionBehaviour for more.
“Don’t Show Again”
If you wanted this behaviour (usually a checkbox at the bottom of an alert dialog, to suppress showing the alert next time), you had to roll your own. In Leopard, NSAlert supports it natively, and also lets you add arbitrary accessory views. This should eliminate a lot of custom windows in nibs and glue code. See NSAlert’s -setShowsSuppressionButton: and -setAccessoryView: methods.
Dock icons for windows and apps, including badges and counts
There’s a new NSDockTile class allowing you to control the dock tile for a minimized window and/or for your app itself. It supports adding or removing the app-icon badge, and also setting a custom badge label, say to show progress or some other status display. This could eliminate a lot of code to create a custom image for the dock, and compositing other stuff into that image.
Tracking the mouse properly
As I previously alluded to, Leopard has a much better alternative to the rather weak and unreliable cursor-rects: NSTrackingArea. Use it to get precise and solid tracking of the mouse (both entered/exited and/or moved), even when your app isn’t active.
Even more text formats
The text systems deals with OASIS Open Document files and ECMA Office Open XML files, and a newer version of Word files too, so you can add a few more Import and Export options to your app for free.
Layout manager improvements
If you’re explicitly using NSLayoutManager for anything, you should know that it now supports non-contiguous layout. This could be a massive performance improvement for your app, if you’re willing to take the time to learn how the implementation has changed. Some very welcome additional minor improvements include getting the baseline offset for a given font, and the ability to display invisibles natively.
Safari 3-style Find results popup
Safari 3 has a nice visual indicator for the results of a Find operation; it’s like a yellowish lozenge shape which pops up over the body of text you’re searching. You have access to this too, via showFindIndicatorForRange: in NSTextView. Use it for good, rather than evil.
Smart links, quotes, and inline image editing
NSTextView supports all these things now, including tooltips for links. You can even query an NSAttributedString to see if it has found an URL at a given position. This could get rid of a lot of custom NSText* object subclasses.
Do good grammar
You might have noticed the new grammar checker (wiggly green underlines) in the Cocoa text system; you have access to it in all the same ways as you’ve had access to the spelling checker for some time now, including providing your own suggested grammatical improvements.
Get rid of a lot of unnecessary bitmaps of buttons
If you have custom buttons in your app, you probably have a lot of bitmaps for the normal state, pressed state, and so on, and a bunch of code to tie it all together. Leopard can help you get rid of it, via NSImage’s -isTemplate and NSCell’s -backgroundStyle additions. Read the docs to find out what it’s all about, but essentially:
- You can specify one bitmap and tell Cocoa that it’s a kind of “mask”, and Cocoa will take care of making it glow in appropriate situations (like the show/hide mini-calendar/tasks buttons in iCal).
- You can tell NSCell how to draw your text, in terms of what kind of background it’s on: dark, light, raised, or lowered. This gets you stuff like the Bookmarks button in Safari (with all its different highlighted/unhilighted/etched/embossed appearances) with only one bitmap.
This is potentially a significant win in terms of app size, memory usage, and your graphics budget. See the documentation for more. Note that NSStatusItem also supports this stuff, so you can potentially get rid of your one-black-and-one-white images there too.
Free images and icons
We’ve all stolen Apple’s icons for things; now we’re officially allowed to. There are lots of new standard images available via NSImage -imageNamed:, including the Safari bookmarks image, all kinds of arrows, the gear icon, the Computer icon, Bluetooth and Bonjour logos, user account icons, the Info icon, and many more. The size of your app could drop significantly, as could your icon-design expenditure. (And don’t worry: NSButtonCell now supports an imageScaling parameter, in case those icons change size in the future).
If you want to play with these in Interface Builder, drag an NSImageView into a window and use the Inspector to set the image using the combo-box; it now lists all the newly-available standard ones.
Drawing complex images and areas by tiling smaller images
Leopard now has two functions called NSDrawThreePartImage() and NSDrawNinePartImage(), which let you easily draw images which have two fixed-width end-caps and one tiled variable-width middle section, or images which have four corner images, four tiled side images, and a tiled central image. These functions are smart about resolution-independence, and could probably replace about twenty or more lines of your code every time they’re used.
NSBox now supports custom background and border colors, and your choice of border width and corner radius. One more custom control subclass you can throw away.
Gradients that aren’t by Chad Weider
Everyone in the Cocoa development world uses CTGradient, and it’s rather awesome. In Leopard, Apple finally catches up with Chad and offers us NSGradient. Check out its methods designed to help you build gradient-editing UI too.
TableViews and OutlineViews enhanced
I’ve often had to create NSTableView subclasses to let me edit the contents of cells (like checkboxes or such), without visually selecting the whole row. Leopard fixes this by letting you choose whether to “track” a cell independent of its editable status. We now have delegate methods to let us support type-to-select natively, both these controls properly support a disabled state, and have a host of improvements in handling drags, contextual menus and inline editing.
If you want that iTunes/Finder-sidebar look, with the etched group titles amongst the rows, you’ve got that too – you can now have “full-width” cells. You can probably get rid of a bunch of custom subclasses of NSTableView, NSTableColumn, and several NSCells.
We’ve been talking about these for years now, and Leopard finally gives you that highlight style in both NSTableView and NSOutlineView. Feel free to make the next iSomething without resorting to custom code.
iTunes Music Store-like path display
The new NSPathControl (and its Cell and ComponentCell cousins) let you have a display like the “breadcrumbs” in the iTunes Music Store, which can also be configured to display as a popup menu or like the Path Bar at the bottom of Finder windows in Leopard. Give it a try in Interface Builder.
Image editing for free
IKImageView (available in Interface Builder) gives you an image view that supports an Image Editing HUD palette, and Preview-style cropping, selection, moving, annotation and more, all with zero code. There’s no reason not to have basic image-editing built into your app wherever you’re dealing with images now.
PDF viewing and browsing for free
Similarly, PDFView (which was already available in Tiger; thanks to Peter Hosey for the correction) gives you Preview-style browsing, selection, zooming and so on for PDFs, and the new PDFThumbnailView even gives you the list of pages down the side. Again, zero code.
Finally unload those bundles
NSBundle now supports unloading. Yes, seriously. Save some memory.
Get info on memory and processors
NSProcessInfo can now tell you the amount of -physicalMemory and also the -processorCount and -activeProcessorCount, without going into Carbon.
Easier priority queues
Take a look at NSOperation and NSOperationQueue (includes dependency management). It could perhaps replace your home-grown implementation.
NSDateFormatter has a host of new symbols (like era names, e.g. “Anno Domini”, quarter names, and new short variants for weekdays, months, etc). This could remove a bunch of hard-coded arrays in your display code if you do a lot of work with dates and calendars. NSCalendar now also has your back for calculating the start and range of a given unit of time around the current moment (like the start of the current week, or month).
NSString has a series of new supported encodings. If you do a lot of conversion between string formats, see if Leopard can’t take over some of the heavy lifting for you.
More efficient expressions in Core Data
NSExpression now supports subquery, aggregate, union, intersect and minus expression types. This means you can save both memory and potentially a lot of code where you previously had to fetch more objects than you needed and filter them yourself. Should be faster, more scaleable, and require less code – definitely check it out if you’re using Core Data with an SQL store.
There are too many improvements to scripting handling to even mention here; please read the Foundation release notes (towards the end) if you use scripting in your app. You’ll be able to remove a lot of nasty workaround code, guaranteed, and you’ll get much more sensible, readable error messages in many cases too.
Working with iCal calendars and other data
The Calendar Store framework lets you access, edit and update iCal data like calendars, tasks, and events, and it’s very easy to use. Supports filtering and searching too, of course.
Check out the PubSub framework if you need to pull down and parse RSS feeds easily; there are examples in /Developer/Examples/ for you to get started with.
Lastly, and hopefully this goes without saying: check out the new and improved objects in Interface Builder. You have some amazing stuff there for nothing, including Automator-related views, AppleScript editor fields, the ability to create your toolbars visually, movie-capturing, and lots of Quartz Composer-related stuff. There’s even a bindings-compatible NSDictionaryController to let you edit the contents of an NSDictionary in an NSTableView, which could eliminate a lot of your controller code.
Oh, and there’s an improved API for creating your own IB objects/palettes, so take a look at that too if you’re interested in contributing back to the developer community, or just making your own dev process a little easier with commonly used custom controls.
That should just about do it for now; I’m sure you want to go and play anyway. Take some time to have a look through Xcode and Interface Builder and get up to speed with the new tools at your disposal – it could make the development time on your next project a lot shorter.