Mac OS 10.7 Lion - My Favorite new APIs

So after months of waiting, Mac 10.7 has finally been released to the general public. Although it has been given some minor spit and polish on the UI front when compared to it’s predecessor Mac OS 10.6, most of the improvements are under the hood. Thankfully the majority of these changes have been made available to developers in the form of APIs. With that in mind I thought I would point out some of my favourite new APIs that I have been using in the developer previews.

NSPopover

NSPopover works a lot like UIPopoverController on iOS. You give an NSPopover an instance of NSViewController (or one of your subclasses), and you can then present this view controller in a popover.

- (IBAction)showPopoverFromButton:(id)sender {
// Create the popover
popover = [[NSPopover alloc] init];

//Set the content view controller
popover.contentViewController = popoverViewController;

popover.animates = YES;

//So we get told when the popover has closed
popover.delegate = (id<NSPopoverDelegate>)self;

[popover showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMaxYEdge];
}

The APIs for NSPopover are nice and simple, but in true Mac OS fashion the delegate callbacks take the form of NSNotifications rather than selectors.

- (void)popoverDidClose:(NSNotification *)notification {
    if ([notification.object isEqualTo:popover]) {
         [popover release]; popover = nil; 
    }
}

If you need to implement something like NSPopover in previous versions of Mac OS, then I recommend taking a look at MAAttatchedWindow.

CoreData

CoreData has had so many updates in Mac OS Lion it is hard to know where to start. Most of the API changes are to incorporate features that are needed to support Versions and iCloud Syncing. What this means is when you modify files Versions and iCloud only want to know the changes that have been made to a file, so they only need to store or transfer the differences between the original and the new file. This approach not only saves space (only the changes are stored, not another whole file), and it also means the versions of the file can easily be compared and contrasted (I am guessing that Apple uses GIT for this). If your application persists any data (and who’s doesn’t?), then you must look at CoreData as it gives you so many things for free.

NSOrderedSet

An ordered set, isn’t that just an array? Well in reality it is, it is an array that makes sure that the objects that it holds are unique and therefore not duplicated. That in itself isn’t that exciting, but what is exciting is that it allows you to have ordered Core Data relationships by simply ticking a box. These ordered relationships do incur a performance penalty over non ordered relationship, so don’t use them for the sake of it.

Concurrency

One of the major issues with CoreData is that NSManagedObjectContexts and therefore the NSManagedObjects that it contains, are not thread safe. In Lion NSManagedObjectContext has the initialiser method initWithConcurrencyType, which allows you to tell an NSManagedObjectContext to mange all of it’s interactions using its own private dispatch queue. This means by using Grand Central Dispatch you can reduce the complexity of concurrency when using CoreData in Mac OS 10.7.

Full Screen Windows

The full screen APIs are incredibly simple to implement (as long as your window resizes to the size of a user’s screen).

All you need to do is set the window’s collection behaviour to support full screen:

[window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];

This one line of code gives you the “full screen button” in the top right hand corner of the window.

If you want to make the window go full screen yourself, you just need to call the toggleFullScreen method on NSWindow:

[window toggleFullScreen:nil];

View based Table Views

My favourite new class is without a doubt NSTableCellView, as it allows you to use a (subclass of) NSView as a table view cell, rather than an NSCell (which is my least favourite class if you are asking). This makes things a lot easier to build custom UIs in a table cell, and also means it can have subviews such as NSButtons that can receive mouse events.

The two data source methods you must implement are:

- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView;

- (NSView *)tableView:(NSTableView *)aTableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row;

Although this makes NSTableView a lot more like UITableView it is important to note that NSTableView doesn’t support sections (as you may have guessed by the numberOfRowsInTableView method not being called numberOfSectionsInTableView). To make things slightly more confusing, NSTableView does however support group rows. Group rows float above the non group rows below it, which means they behave like iOS section headers.

You can tell the table view that a cell is a group row by using the delegate method:

- (BOOL)tableView:(NSTableView *)tableView isGroupRow:(NSInteger)row;

If you are creating a custom NSTableCellView in code, don’t forget you can override isFlipped to flip the coordinate system and make it like the iOS co-ordinate system.

Also don’t forget that as NSOutlineView is a subclass NSTableView, so it also supports view based cells.

In App Purchase

In App Purchase for iOS has been in the press for all the wrong reasons recently, but it is a great API for Mac OS X developers to have, so they can unlock different features in their applications. The API is very similar to it’s iOS counterpart besides when it comes to receipt validation. For more information on this I recommend watching the WWDC session 510, which is all about In App Purchase.

Push Notifications

Another feature ported across from iOS, but this time with less features. On Mac OS push notifications can only contain a badge value and not an alert and/or sound.

So thats a wrap up of my favourite new APIs in Lion, the standout ones for me being View Based Table Views and NSPopover. There have been so many updates I recommend looking through the change list, as you never know what you might find.