Objective-C

OS X Mountain Lion API Highlights

3

With Mountain Lion appearing in the AppStore just 1 year after its predecessor Lion (371 Days to be precise), it should come as no great surprise that there isn’t the large amount of new APIs that usually comes along with a major update to OS X. Nevertheless there are a few stand out APIs that are worth pointing out.

Notification Center

Notification Center was a major feature of iOS 5 and now it makes its way to the Mac in Mountain Lion. If your coming from iOS using UILocalNotification or if your coming from Growl! on OS X you should have no problems getting up to speed with notifications, which on the Mac are referred to as NSUserNotification.

To post a notification you will need to create a NSUserNotification object and set the title and optionally the subtitle and/or informative text.

NSUserNotification *userNotification = [[NSUserNotification alloc] init];
 
userNotification.title = notificationTitle;
userNotification.subtitle = notificationSubtitle;

If your notification is actionable you can set the text of 2 additional buttons using the actionButtonTitle and otherButtonTitle properties.

Like UILocalNotification you can set a notification to be shown at a given time (e.g. for an alarm) using the deliveryDate property.

When you have finished configuring your notification simply tell the NSUserNotificationCenter to deliver it:

[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:userNotification];
[userNotification release];

By default notifications are only shown if your application is not in the foreground, which may seem confusing at first as Xcode always show notifications regardless of wether it is in the foreground or not.

Thankfully all you have to do is become the delegate of the user notification centre:

[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:(id)self];

Then respond to the should present notification delegate method:

- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification{
    return YES;
}

It is important to note that only signed Apps (Gatekeeper, MAS etc) can post notifications.

Sharing

iOS has always had the ability to share photos and videos by E-mail and SMS and more recently by Twitter, it is this system wide sharing that NSSharingService tries to solve.

You can present your own UI for sharing, but most of the time you will want to use NSSharingServicePicker which you can present from a button.

The first thing you will need to do is to configure the button to send its action on mouse down

[shareButton sendActionOn:NSLeftMouseDownMask];

To share files you need to know their file system URLs and simply pass these to NSSharingServicePicker. If you present this from the button the OS will take care of everything for you:

NSSharingServicePicker *sharingServicePicker = [[NSSharingServicePicker alloc] initWithItems:fileURLs];
 
[sharingServicePicker showRelativeToRect:[sender bounds]
                                  ofView:sender
                           preferredEdge:NSMinYEdge];
[sharingServicePicker release];

You can add your own sharing services in your app to the sharing service picker, but it is impossible for you to add your service to the OS and therefore make available for other apps to use.

Game Center

If you are familiar with Game Center on iOS you will be familiar with Game Center on OS X. Matchmaking, Achievements and your Friends are all here for your multiple device gaming pleasure.

iCloud

In Mountain Lion Apple has introduced the iCloud Document Browser, which means that all apps have standard way of displaying their Documents in the Cloud.

EventKit

EventKit comes directly from iOS and replaces the Calendar Store for interacting with a user’s calendars, events and reminders. The major benefit of Event Kit is that you can use the exact same code to interact with calendars on both iOS and OS X.

Security Scoped File URL Bookmarks

1

Sandboxed applications (without any additional entitlements) live within their container (~/Library/Containers/apps.bundle_identifier) and have no access to the rest of the File System, no access to the Internet, no access to Hardware such as the Camera, Microphone, USB Devices and Printing and has no access to User’s Data such as the Address Book, Location or Calendar.

Now this may seem a little extreme, but besides file system access all of these features can be enabled by requesting the relevant entitlement. For these features everything “just works”, but be warned you may be quizzed by the Apps Review Team why you require a given entitlement, so don’t just include them for the sake of it … or for analytics.

So now on to files…

When you sandbox your application you will have the following entitlements file (typically called app_name.entitlements):

 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.security.app-sandbox</key>
	<true/>
</dict>
</plist>

com.apple.security.app-sandbox simply enables app sandboxing for the given target:

com.apple.security.app-sandbox


Enables App Sandbox for a target in an Xcode project

As you can’t just access any file on the file system, the user has to select them (which means the powerbox will give you temporary access to the URL of the file). To do this the user can use drag and drop, or use NSOpenPanel/NSSavePanel. For this example we will use NSOpenPanel for clarity. To use NSOpenPanel/NSSavePanel you need to include the following entitlement:

com.apple.security.files.user-selected.read-write


Read/write access to files the user has selected using an Open or Save dialog

NSOpenPanel is trivial to implement and you get access to a file URL in the completion handler:

NSOpenPanel *openPanel = [NSOpenPanel openPanel];
 
[openPanel beginSheetModalForWindow:[self window] 
completionHandler:^(NSInteger result){
 
if (result == NSOKButton) 
{
    NSURL *openPanelFileURL = [openPanel URL];
}
 
}];

By using NSOpenPanel you now have access to the given file URL (and therefore file) until your application quits. Under certain circumstances you also get access to the file URL when you application launches if the application supports resume.

So what if you need to access files across launches?

You need another entitlement of course, in this case you have 2 choices depending on if your Application is a Document Based Application:

com.apple.security.files.bookmarks.collection-scope


Ability to use document-scoped bookmarks and URLs

or a Non-Document Based Application:

com.apple.security.files.bookmarks.app-scope


Ability to use app-scoped bookmarks and URLs

Assuming your application is a Non-Document Based Application your entitlements file will now look like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.security.app-sandbox</key>
	<true/>
	<key>com.apple.security.files.user-selected.read-write</key>
	<true/>
	<key>com.apple.security.files.bookmarks.app-scope</key>
	<true/>
</dict>
</plist>

First of all you need to get access to the file URL in the same way as you did before, but this time you are going to create a bookmark out of it using NSURLBookmarkCreationWithSecurityScope:

NSURLBookmarkResolutionWithSecurityScope


Specifies that the security scope, applied to the bookmark when it was created, should be used during resolution of the bookmark data.

NSError *error = nil;
NSData *bookmarkData = nil;
 
bookmarkData = [openPanelFileURL 
bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
includingResourceValuesForKeys:nil
relativeToURL:nil
error:&error];

You can now store this bookmark (which is just a NSData object) in any way you choose, as long as you can retrieve it later.

When you want to access this file you need to convert the bookmarkData into a file URL:

NSError *error = nil;
BOOL bookmarkDataIsStale;
NSURL *bookmarkFileURL = nil;
 
bookmarkFileURL = [NSURL 
URLByResolvingBookmarkData:bookmarkData
options:NSURLBookmarkResolutionWithSecurityScope
relativeToURL:nil
bookmarkDataIsStale:&bookmarkDataIsStale
error:&error];

The URL returned includes a “security scope” appended to it (although this cannot be assumed):

file://localhost/Users/ObjColumnist/Desktop/File?applesecurityscope=373861333331353430643963323736623939346438646161643134663339363061396361306534303b30303030303030303b303030303030303030303030303032303b636f6d2e6170706c652e6170702d73616e64626f782e726561642d77726974653b30303030303030313b30653030303030323b303030303030303030306535363566373b2f75736572732f7370656e6365722f6465736b746f702f77617463686564

You then need to tell the OS that you are going access this file URL:

[bookmarkFileURL startAccessingSecurityScopedResource];

This allows you to do anything you want with that file URL, typically you will use NSFileManager to do this.

Once you are done accessing this file URL you MUST tell the OS, failing to do so will leak kernel resources and prevent you from accessing secured files until you quit your application.

[bookmarkFileURL stopAccessingSecurityScopedResource];

This wraps up Security Scoped File URL Bookmarks on OS X and how you can access files outside of you application’s sandbox container. It is important to note that you don’t have to do this for files that reside in your application’s container, and this article doesn’t do any error handling when converting URLs to Bookmarks and Vice Versa.

Is the Latest Always the Greatest?

2

After watching the various feeds regarding Apple’s media event this Wednesday, I picked up my iPad (1st generation) and went to download the new iPhoto app. Unfortunatley I was out of luck, as it said I needed a camera (why? If I had a Mac without a iSight Camera would Apple prevent me from using iPhoto on my Mac?). Thankfully I have an iPhone 4S, so I went to the App Store and was presented with the following Updates screen:

Now at first glance you may just think Apple have been busy, but if you look closely they updated some of their existing applications to requires iOS 5.1, a version of the OS which had only been available for a few minutes (and a version of the OS that refused to download due to server load!!!).

This made me think, If Apple requires users to update their devices to latest version of the OS to use their Apps, why don’t all developers?

The common approach of developers is to change the minimum specification of their applications only when they release a major version, but why does it have to be this way?

If we only supported the latest version of OS (and I mean even a point release) we would have the benefits of:

  • Only having to test on one version of the OS
  • You get to use the latest APIs
  • Hopefully the newer version of the OS has less bugs than the previous versions

Now using the latest APIs actually has a number of benefits:

  • You have to Write Less Code
  • More chance of getting featured by Apple and other publications as your using new features
  • Happy Developers

So whats the downside? The only downside is quite a big one and that is:

  • Reduces the number of people that can use your app

But who are these users that don’t run the latest version of an OS? All iOS devices that have been avaliable for purchase in the last 2 years (not many people keep their phones beyond this) can upgrade to the latest OS for free. Since Over the Air Updates where introduced in iOS 5, the process of upgrading the OS on your device has become quick and painless. So my argument is, if all applications required the latest OS version to work, then maybe users would be more eager to upgrade their OS anyway…

We have something you really have to see. And touch – Media Event Predictions

2

So it is time for Apple’s first Keynote of the year (or do we count the educational event in January? … it did show up in the Keynote Podcast Feed after all), and the one prediction that everyone seems to be agreeing upon is that we will see the unveiling of the iPad 3, but what will be new…

iPad 3


Retina Display

The iPad 3 will have a 2048×1536 Retina Display (4 times as many pixels as the iPad 2′s display), meaning that text will be sharp and crisp and your be able to watch 1080p videos with (quite a lot of) pixels to spare. To put this into perspective, the 27″ iMac has a resolution of 2560×1440, which means the iPad will actually have more lines on the screen than the 27″ iMac. There is an unfortunate side effect of the iPad getting a Retina Display, and that is applications will probably increase in size with all of the iPad @2x images.

A6 Quad Core Processor

One thing that we know for sure is that the iPad 3 will need quite a bit of a speed bump to push all those pixels around the screen, but will it be a newer Dual Core A5 or a Quad Core A6 Processor? One of the rumors is that the iPad 3 will be slightly thicker than its predecessor, and I think this is to accommodate a bigger battery for a Quad Core Processor.

Improved Camera

The iPhone 4S’s camera is the one of best cameras that you will find on a smartphone, the iPad 2′s camera on the other hand is probably not as good as the original iPhone’s. The Retina Display would emphasise how bad the cameras are on the iPad, so I expect Apple to bump the spec of both of the cameras so that they can at least both record video at 1080p.

LTE

It is early days for LTE, but I don’t think that there is any doubt that it will be the standard for the next few years, and unlike CDMA this will include outside of the US too. Maybe LTE is why the iPad 3 will put on a few pounds?

What else?


AppleTV 3

Continuing on the theme of 1080p, I think that we will finally get an AppleTV that is able to play 1080p videos which will also mean…

1080p iTunes Videos

I think Apple will start selling 1080p videos, which means that they are (theoretically) the same quality as Bluray. This means that videophiles will have nothing left to complain about… unless they still have a dial up internet connection as those video files will be huge.

What we won’t see


Thunderbolt Syncing

Am I the only person who still syncs their iPad using a USB cable? Hopefully I am not, but it would be good if you could sync your iPad in seconds over Thunderbolt. Unfortunately I don’t even think Apple will be adding to the tiny (mini? … nano?) list of device that currently uses Thunderbolt.

128 GB of Storage

With 1080p Videos and Retina apps everyone would like a bit more storage wouldn’t they?

iOS 6

I don’t think we are too far away from the developer preview of iOS 6, but I think that Apple will have an event just for iOS 6 (especially if it is a major release).

Shipping a 1.0 is Hard

0

The first version of an application is different to any other, and it is the hardest one to actually ship. This is especially true if you are an indie developer.

When you start a new application you probably have a list of features and a sketch of what you think/hope/wish the 1.0 version of your application will look like. As an indie developer you are the only one that knows exactly what is on this list, but you often feel like you can’t release an application until the whole list is completed, even though nobody else would be any the wiser.

The other major difference about a 1.0 version of an application is the lack of immediate pressure to release it. When you have released an application you are often pressured into releasing an update for a new feature or simply to fix some bugs. As an indie developer the only pressure you get is from yourself (and I try not to moan at me too often).

So over a week ago I finally decided my baby was ready to see the world, so I sent off the 1.0 version of my application Actionify to Apple and waited for it to go through the review process. To my pleasant surprise there was no problems first time round (Apple usually find something) and Actionify was released on Friday. Actionify is a GTD inspired Task Manager, that also offers a cloud sync subscription that allows users to collaborate on Projects. If you want to know more about it, you can click on the link here, but I won’t overload this post info. I am very pleased with how Actionify has turned out, the 1.0 misses a few features from my original list but also some additions that I added due to the feedback I received during the beta testing (thank you testers!!!). Inevitable it took longer than I had originally hoped, but this was mainly down to me underestimating the amount of effort and paperwork it took to set up a limited company (in the UK) and everything that goes with that (e.g. Banking, Transferring my iTunes Connect Account etc etc). In terms of development time the project probably only over run by 1 or 2 months, while this is not ideal, it isn’t to bad either.

In terms of technology, Actionify requires Mac OS 10.7 as the UI is mainly built with view based table views and the new Core Data APIs. I think view based table views shaved about 2 months off of my development time, so support for 10.6 wasn’t really an option for me. 10.7 also has a JSON Parser (NSJSONSerialization) and Popovers (NSPopover) built in, and although there are open source projects that offer similar functionally, I prefer to only depend on code by Apple and myself (rightly or wrongly) wherever possible.

The application syncs with a Rails application that I host on Heroku, and I couldn’t recommend Rails and Heroku enough. Rails is a great framework and Ruby is a great programming language, the best thing about Rails (for a non web developer) is everything has its place. Rails forces you to have a certain folder structure and I found this extremely beneficial … you can also add features with only a few lines of code which can only be a good thing. Heroku’s main benefit is you don’t have to think about servers and you just have to worry about your app. You simply deploy your code using a git push and you’re done. Moreover the majority of basic Heroku Add Ons are free, so you can start using Heroku without any risk (I am honestly not on commission, I just like it :) ).

I want to end this post by saying no matter how many times you release an application, seeing other people downloading it and using it is always the best feeling a developer can get, so if you can … SHIP IT!!!

Keeping the Static Analyzer Happy: Prefixed Initializers

3

The latest version of Xcode ships with LLVM 3.0 as it’s default compiler, and one of the first things that you will notice is that is a lot more thorough when it analyses your code compared to previous versions (which can only be a good thing). One thing that the static analyser now warns you about, is that you are over releasing objects that are returned from prefixed intalizer methods (init), such as in a category (for my previous posts on categories see here and here).

For example my NSString category has the following method:

- (id)MCSM_initWithComponents:(NSArray *)components 
seperatedByString:(NSString *)seperator;

And it’s implementation looks like this:

 
- (id)MCSM_initWithComponents:(NSArray *)components 
seperatedByString:(NSString *)seperator{
 
    NSMutableString *componentizedString = [NSMutableString string];
 
    NSUInteger i = 0;
    for(NSString *component in components){
 
        if(i == 0)
        {
            [componentizedString appendString:component];
        }else{
            [componentizedString appendFormat:@"%@%@",seperator,component];
        }
 
        i++;
 
    }
    return [self initWithString:componentizedString];
}

This method takes an array of strings, and joins together using the separator parameter and can be used in the following way:

 
NSString *string = nil;
NSArray *components = [NSArray arrayWithObjects:@"one",@"two",nil]; 
string = [[NSString alloc] MCSM_initWithComponents:components seperatedByString:@","];
NSLog(@"%@",string);
[string release];

This would output:

one,two

As this method is in a category of NSString I don’t want it to clash with any other implementations. The common practise in Objective-C is to prefix categories methods (due to the lack of namespaces), so I have with MCSM_. The issue is that the static analyser will now think that this method returns an autoreleased object, as the method does not begin with init, new, copy or alloc. This means when you release the object the static analyser will complain about you over releasing an object.

So how do you fix this?

To fix this you can tell the compiler that the method returns a retained object by using the source annotation NS_RETURNS_RETAINED, which means your interface would look like the following:

 
- (id)MCSM_initWithComponents:(NSArray *)components 
seperatedByString:(NSString *)seperator NS_RETURNS_RETAINED;

Instead of NS_RETURNS_RETAINED you can also use __attribute__((ns_returns_retained)), which is a longer way of writing the same thing:

- (id)MCSM_initWithComponents:(NSArray *)components 
seperatedByString:(NSString *)seperator __attribute__((ns_returns_retained));

So thats all fixed? Unfortunately not quite yet. The static analyser will now complain about a memory leak, as we have allocated a NSString by doing [NSString alloc], but then it isn’t referenced again in our code. For a method that begins with init, the static analyser knows that the method consumes the variable (which means it releases the parameter upon completion), and that is the behaviour we need.

To do this we have to use the source annotation __attribute__((ns_consumes_self)) in conjunction __attribute__((ns_returns_retained)), which means your interface will look like:

- (id)MCSM_initWithComponents:(NSArray *)components 
seperatedByString:(NSString *)seperator __attribute__((ns_consumes_self))__attribute__((ns_returns_retained));

And that will fix it.

Summary:

You don’t need to use the source annotations if your code obeys the Objective-C naming conventions, but in certain circumstances like the one above you need to help the Static Analyser do its job. As LLVM forms the the backbone of Automatic Reference Counting (ARC), you still need to do this even if your not retaining and releasing memory yourself.

Adding Block Support to Existing Classes (Without Subclassing)

1

Blocks are great aren’t they? Amongst many other things, they allow you to put all your completion logic right next to where you call an asynchronous method. Apple has added block support for completion handlers in such APIs such as Core Animation, in fact I have already done a post on this previously. But what do you do, if the class you want to use is stuck in the past and still uses the older delegate style approach. This is where you have to write a method to handle all the delegate callbacks for a given class? Well thankfully there is a nice and clean way of adding block support to a class using a category.

I’ve previously written 2 posts on categories (which you can find here and here), and how they allow you to extend a class’s functionality by adding additional methods to it without subclassing it. The key word being methods (or indeed selectors if your getting technical), and not properties or instance variables. If you need to call a block after an asynchronous action has completed, you’re going to have to store it somewhere in the meantime, and that is the main focus of this post.

Take UIAlertView for example, you need to register for a callback when the user presses a button.

So you’d often have something like:

- (IBAction)showAlert:(id)sender{
 
UIAlertView *alertView = nil;
 
alertView = [[UIAlertView alloc] initWithTitle:@"YES or NO"
message:@"Select One" 
delegate:self 
cancelButtonTitle:@"NO" 
otherButtonTitles:@"YES", nil];
 
[alertView show];
[alertView autorelease];
}

Then you would need to implement a method with the correct signature to handle it:

- (void)alertView:(UIAlertView *)alertView 
didDismissWithButtonIndex:(NSInteger)buttonIndex{
if(buttonIndex == 1)
{
//Do Something
}
}

This may look fine in the above example, but in a real iOS application the callback method may have to handle lots of different alert views, and we still have the handler code separated from where we actually setup and show the alert view.

So how can we solve this?

We are going to add a completion handler to UIAlertView, which doesn’t return anything and takes the button index we get given by the UIAlertViews delegate method as a parameter. To keep things clean we will define our completion handler in our categories header:

typedef void(^MCSMUIAlertViewCompletionHandler)(NSUInteger buttonIndex);

So the first thing you will need to do is set the completion hander block on an alert view and store it for when we get the delegate callback. For this we will use the Objective-C runtime function: objc_setAssociatedObject.

The objc_setAssociatedObject function takes 4 parameters:

  1. The object that you want to add the association too, in this case the UIAlertView
  2. The unique key so you can retrieve the value later
  3. The value you want to associate, which in this case is the completion handler block
  4. The association policy, which tells the runtime wether this association retains, copies or assigns the value.

The best way to describe how this function works, is that it treats an object like and NSDictionary. It allows you to set a given value for a given key, but unlike NSDictionary you can specify if the value is assign, retained or copied.

To use this method you need to include the runtime header:

#import <objc/runtime.h>

And we will define our key as a constant to keep things tidy, and so we don’t make any typos later on:

NSString * const MCSMUIAlertViewCompletionHandlerKey = @"MCSMUIAlertViewCompletionHandlerKey";

Then in another category method on UIAlertView all you need to do is set the alert view as its own delegate, and store the block as an associated object:

- (void)MCSM_setCompletionHandler:(MCSMUIAlertViewCompletionHandler)handler{
self.delegate = (id<UIAlertViewDelegate>)self; 
 
objc_setAssociatedObject(
self, 
MCSMUIAlertViewCompletionHandlerKey,
handler,
OBJC_ASSOCIATION_COPY_NONATOMIC);
 
}

As the UIAlertView is now it own delegate, it will receive the alertView:didDismissWithButtonIndex: callback. In this method you will need to retrieve the completion handler block so you can call it with the button index argument. To do this you will need to use another Objective-C runtime function objc_getAssociatedObject

The objc_getAssociatedObject function takes 2 parameters:

  1. The object to retrieve the association from
  2. The unique key for the association

This will mean that you end up with a method looking like this:

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex{
 
MCSMUIAlertViewCompletionHandler handler = nil;
//Get the Handler
handler = (MCSMUIAlertViewCompletionHandler)objc_getAssociatedObject(
self,
MCSMUIAlertViewCompletionHandlerKey);
 
//If there is a handler call the handler
if(handler)
{
  handler(buttonIndex);
}
 
//Release the block by setting the associated object to nil
objc_setAssociatedObject(
self, 
MCSMUIAlertViewCompletionHandlerKey, 
nil, 
OBJC_ASSOCIATION_COPY_NONATOMIC);
}

So now that we have added this category to UIAlertView, all we have to do is update the code that creates and shows the alert view:

- (IBAction)showAlert:(id)sender{
 
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"YES or NO"
message:@"Select One" 
delegate:self 
cancelButtonTitle:@"NO" 
otherButtonTitles:@"YES", nil];
 
[alertView MCSM_setCompletionHandler:^(NSUInteger buttonIndex){
if(buttonIndex == 1)
{
//Do Something
} 
}];
[alertView show];
[alertView autorelease];
}

You can grab the code for this on Git Hub here and have a play with it yourself.

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.

Performing a block of code on a given thread

8

This post has been a long time coming, mainly because I cannot claim that I done any of the work to make it possible, for that I have to thank the Big Nerd Ranch and Landon Fuller. Nevertheless, I have found the following category so useful that I thought I would do a post on it anyway.

When I first started using blocks, I thought “I have this block of code, can’t I just run it on a given thread?”. The answer is (thankfully) yes, but Apple don’t supply a simple API to do this in Mac OS or iOS. The category below solves this issue:

@implementation NSThread (MCSMNSThreadCategory)
 
+ (void)MCSM_performBlockOnMainThread:(void (^)())block{
	[[NSThread mainThread] MCSM_performBlock:block];
}
 
+ (void)MCSM_performBlockInBackground:(void (^)())block{
	[NSThread performSelectorInBackground:@selector(MCSM_runBlock:)
						      withObject:[[block copy] autorelease]];
}
 
+ (void)MCSM_runBlock:(void (^)())block{
	block();
}
 
 
- (void)MCSM_performBlock:(void (^)())block{
 
	if ([[NSThread currentThread] isEqual:self])
	block();
	else
	[self MCSM_performBlock:block waitUntilDone:NO];
}
- (void)MCSM_performBlock:(void (^)())block waitUntilDone:(BOOL)wait{
 
	[NSThread performSelector:@selector(MCSM_runBlock:)
					 onThread:self
				   withObject:[[block copy] autorelease]
				waitUntilDone:wait];
}
 
- (void)MCSM_performBlock:(void (^)())block afterDelay:(NSTimeInterval)delay{
 
	[self performSelector:@selector(MCSM_performBlock:) 
			   withObject:[[block copy] autorelease] 
			afterDelay:delay];
}
 
@end

This category adds a set of (simple) methods to the NSThread class, that allows you to run a block on any thread that you have a reference to. (You may notice that the Big Nerd Ranch prefix their category methods with BNR and I use MCSM, this is due to Objective-C not supporting namespaces).

For more information on blocks, see Apple’s Blocks Programming Topics documentation.

Alongside blocks Apple introduced Grand Central Dispatch (GCD) in Mac OS 10.6, and I suggest that anyone implementing processor intensive tasks that require code to be executed off of the main thread should try and implement their code using GCD. That being said there are situations (predominantly due to the use of legacy APIs/libraries) whereby the use of a dedicated thread is still required.

Say you have a network thread (networkThread), and on this thread is network socket which is maintaining a persistent connection to a server, and a parser for the data that is received on that socket. (There is a common mistake I see, whereby programmers do the network I/O off of the main thread but still parse the data on the main thread, thus locking up the application’s UI when the data is being parsed).

Normally the data you want to send over the network originates from something that has been triggered from the application’s UI, and therefore the main thread. You then need to get this data onto the network thread so it can be sent.

Say you wanted to send a person’s first name (firstName), last name (lastName) and company name (companyName) over the network.

Ideally you would have a method that looked something like:

- (void)sendFirstName:(NSString *)firstName 
lastName:(NSString *)lastName 
companyName:(NSString *)companyName;

This method would convert the data into a format that can be sent over the network (e.g. XML, JSON etc), and queue it on the socket for sending.

The issue is if two threads try to use the same socket at the same time your application will crash, so this method can only ever be called from the networkThread. This is also relevant for other non-thread safe APIs.

So for this example we will rename it to:

- (void)onNetworkThreadSendFirstName:(NSString *)firstName 
 lastName:(NSString *)lastName 
companyName:(NSString *)companyName;

and keep the original method for use on the main thread.

So how do you call a method on another thread?
Well you can’t directly, you have to use:

- (void)performSelector:(SEL)selector 
 onThread:(NSThread *)thread 
 withObject:(id)object 
 waitUntilDone:(BOOL)wait;

The only problem with this is that the selector you call can only take one argument (using the withObject parameter), and in this example we want to pass 3.

So what we need to do is put all of the arguments into one object. You could do this using an array (you would need a fixed amount of arguments to do this), a custom object (overkill if it is only going to be used as an argument to a method) or a dictionary which is what I will be using.

- (void)onNetworkThreadSendArguments:(NSDictionary *)arguments;

This means that you would end up with an implementation such as the following:

 
- (void)sendFirstName:(NSString *)firstName 
 lastName:(NSString *)lastName 
 companyName:(NSString *)companyName{
 
NSDictionary *arguments = [NSDictionary dictionaryWithObjectsAndKeys:
firstName,@"firstName",
lastName,@"lastName",
companyName,@"companyName",nil];
 
[self 
performSelector:@selector(onNetworkThreadSendArguments:) 
onThread:networkThread 
withObject:arguments 
waitUntilDone:NO];
 
}
 
- (void)onNetworkThreadSendArguments:(NSDictionary *)arguments{
 
NSString *firstName = [arguments objectForKey:@"firstName"];
NSString *lastName = [arguments objectForKey:@"lastName"];
NSString *companyName = [arguments objectForKey:@"companyName"];
 
[self 
onNetworkThreadSendFirstName:firstName
lastName:lastName
companyName:companyName];
}
 
- (void)onNetworkThreadSendFirstName:(NSString *)firstName 
lastName:(NSString *)lastName 
companyName:(NSString *)companyName{
	//format and send data
}

So before 10.6 this technique would be common practise, but it means you have to write extra methods to pack and unpack arguments for cross thread calls.

Thankfully we can get this down to 1 method call using our block category on NSThread:

 
- (void)sendFirstName:(NSString *)firstName 
 lastName:(NSString *)lastName 
 companyName:(NSString *)companyName{
 
	[networkThread MCSM_performBlock:^{
		//format and send data
	}];
}

As the block of code is always executed on the network thread, this method can be called from any thread. As you can see blocks can be very useful even when used without Grand Central Dispatch.

This category is available on github here.

Go to Top