Archive for July, 2011

Mac OS 10.7 Lion – My Favorite new APIs

5

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.

Creating singletons using dispatch_once

1

Love them or loathe them, sometimes you need to have a singleton. In fact every iOS and Mac OS application has at least one, UIApplication or NSApplication.

So what is a singleton? Wikipedia defines it as:

In software engineering, the singleton pattern is a design pattern used to implement the mathematical concept of a singleton, by restricting the instantiation of a class to one object.

Or as I would put it:

A singleton is a class, where only one instance of it can instantiated.

Although this is the actual definition of a singleton, this isn’t always the case in the world of Foundation. NSFileManger and NSNotificationCenter for example, are usually accessed through their class methods defaultManager and defaultCenter respectively. Although not strictly a singleton, these class methods return a shared instance of that class that developers can then access throughout their code. It is this approach that we will be looking at in this post.

There has always been a debate on the best way to implement the singleton pattern using Objective-C, and developers (including Apple) seem to have been changing their minds every couple of years. When Apple introduced Grand Central Dispatch (GCD) (in Mac OS 10.6 and iOS 4.0) they introduced a function that is perfect for implementing the singleton pattern.

This function is dispatch_once:

   void dispatch_once(
   dispatch_once_t *predicate,
   dispatch_block_t block);

This function takes a predicate (which is a long, that in reality acts as a BOOL) that the dispatch_once function uses to check if the block has already been dispatched. It also takes the block that you wish to only be dispatched once for the lifetime of the application, for us this is the instantiation of our shared instance.

Not only does dispatch_once mean that your code will only ever get run once, it is also thread safe, which means you don’t have to bother with using anything like @synchronized to stop things getting out of sync when using multiple threads and/or queues.

This is verified by Apple’s GCD Documentation:

If called simultaneously from multiple threads, this function waits synchronously until the block has completed.

So how would you use this in practise?

Well lets say you have a Account Manager class, and you want to access a shared instance of this class throughout your application. You can simply implement a class method like the one below:

+ (AccountManager *)sharedManager
{
        static AccountManager *sharedAccountManagerInstance = nil;
        static dispatch_once_t predicate;
        dispatch_once(&predicate, ^{
                sharedAccountManagerInstance = [[self alloc] init]; 
        });
    return sharedAccountManagerInstance;
}

This means whenever you want access this shared instance all you need to do is:

AccountManager *accountManager = [AccountManager sharedManager];

And that’s all there is to it, you now have a shared instance that you can access throughout your application, which will only be created once.

This approach has many advantages:

  1. It is thread safe
  2. It will keep the static analyser happy
  3. It is compatible with Automatic Reference Counting (ARC)
  4. It only requires a small amount of code

The only disadvantage with this approach is that it will still allow a non shared instance to be created:

AccountManager *accountManager = [[AccountManager alloc] init];

Sometimes you will actually want this behaviour, but it is something you need to be aware of when you really only want one instance of a class to ever be instantiated.

Go to Top