Tag: cocoa

 

Keychained

I’m working on an OSX interface to a web service right now. Of course, one of the requirements is for a username and password. Simple — just use keychain, right?

Well, it might be simple, apart from the fact that Keychain Services has a hoary old API. It’s C-based, and is like taking a step back in time to the early ’90s. After using the rest of the Cocoa Objective-C APIs, it’s a real shock.

  // Try to find a password.
  const char *svc = "ABCD";
  SecKeychainItemRef itemRef = nil;
  OSStatus st = SecKeychainFindGenericPassword(NULL, strlen(svc), svc, 0, NULL,
                                            NULL, NULL, &itemRef);
 
  if (st == noErr) {
    // use the keychain item
  } else {
    NSLog(@"Ooops, got error status %d", st);
  }

Pulling items out of a keychain is even more long winded.

  UInt32 length;
  char *password;
  SecKeychainAttribute attributes[4];
  SecKeychainAttributeList list;
  // list attributes we want to read.
  attributes[0].tag = kSecAccountItemAttr;
  attributes[1].tag = kSecDescriptionItemAttr;
  attributes[2].tag = kSecLabelItemAttr;
  attributes[3].tag = kSecModDateItemAttr;
 
  list.count = 4;
  list.attr = attributes;
  // Can pass NULL for password if not needed.
  OSStatus status = SecKeychainItemCopyContent(item, NULL, &list, &length, (void **)&password);
 
  if (status == noErr) {
    // Use the now filled-in attributes.  NB: Password is NOT zero terminated, but "length" long.
  } else {
    // Complain bitterly.
  }
  SecKeychainItemFreeContent(&list, password);

So what to do? Of course, it’d be great if there were a nice, OO wrapper. I had a quick look and found EMKeyChain (on github). Here’s a sample usage:

  NSString *password = [EMGenericKeychain passwordForUsername:@"dom"
                                                      service:@"MyService"];

It’s a world of difference. Sadly, EMKeychain doesn’t quite support the use case I want. I don’t necessarily know the username in advance. This leaves me with a few choices:

  1. Give up, and just use the vanilla Keychain API. Bleurgh.
  2. Fix EMKeychain to support my use case.
  3. Use the preferences API to store the username, and then EMKeychain will work as expected.

I’m leaning quite strongly towards the third option.

Embedding Cocoa Frameworks

I’m (re)learning Cocoa at the moment. I’m working my way through the wonderful Cocoa Programming for Mac OS X. But for my first solo project, I found myself needing to XML-RPC. I took one look at Web Services Core Programming Guide and barfed. After a quick hunt, I found Eric Czarny’s lovely XMLRPC project for cocoa. This looked exactly like what I needed.

I had one small problem though — it’s a framework. I’ve not used one before. How do I actually get this code included in my project?

After looking at the Framework Programming Guide, there are a few options for embedding the framework into my project (embedding is the only sensible choice — I don’t want the user to have to install this on their system).

  1. Build and install the framework locally, then just drag it into my project.
  2. Build the framework, and check the results into my source control system.
  3. Embed the framework into my own project, so it gets built on its own each time.

The first option means that the build is no dependent on my workstation. The second option works, but I dislike binaries in version control (and how non-reproduceable these can be). The third option is ideal as it means the build is self contained. However, it’s also the most non-obvious to implement.

After quite a few misdirected searches, I eventually found Jonathan “wolf” Rentzsch’s marvellous tutorial Embedded Cocoa Frameworks. Unfortunately, it’s gone 404. Archive.org has a copy, including the 8 minute screencast.

In case it goes away again, here’s what I did to integrate the XMLRPC framework. I’ll start with a brand-new Cocoa project, MyApp.

Brand new Xcode project

Next you need to git clone git://github.com/eczarny/xmlrpc.git in a nearby place (a sibling directory is ideal, though you could set up inside MyApp using git submodules).

Before we can get started, we need to open up the XMLRPC project and make a couple of changes. First, we need to ensure that the Configurations match the ones in my project. Otherwise, Xcode will use the default configuration, which may produce unexpected results. I did this by duplicating Development into Debug.

XMLRPC Project Configurations

Now, build the XMLRPC project (⌘-B). You should end up with …/xmlrpc/build/Debug/XMLRPC.framework. Right-click on MyAppFrameworksLinked Frameworks and choose Add…Existing Frameworks….
Navigate to the previously built framework and select it. In the sheet that pops up, ensure that you choose “Reference Type: Relative to Project,” as well as ensuring that MyApp is selected in “Add To Targets.”

Add XMLRPC framework to MyApp

If you’ve been fastidiously keeping an eye on things in git (as I like to do), you can see the changes in your xcode project file. As well as introducing a reference to the framework directory, you will also see that the FRAMEWORK_SEARCH_PATHS build setting has been set up for you:

FRAMEWORK_SEARCH_PATHS = (
  "$(inherited)",
  "\"$(SRCROOT)/../xmlrpc/build/Debug\"",
);

Unfortunately, this the point at which I realised that what I was doing wouldn’t work. We’re linking against the Debug configuration of the framework. I need to embed a reference in my project that’s independent of which configuration the XMLRPC project was built with. In order to do that, we have to modify the XMLRPC project a bit more.

Go back to the XMLRPC project and right click on the XMLRPC target. Choose Add…New Build Phase…New Run Script Build Phase. Type in the code:

Add Run Script phase to XMLRPC project
set -x
rm -rf "${BUILD_DIR}/${FULL_PRODUCT_NAME}"
cp -r "${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}" "${BUILD_DIR}/${FULL_PRODUCT_NAME}"

The net effect is to copy the framework from …/xmlrpc/build/Debug to …/xmlrpc/build. This means that there’s a single location to pull in. You may wish to rename the Run Script phase to something like “Run Script: Copy to well-known location.”

In case you’re wondering, I figured out which environment variables to use by looking at the build output, as it has another Run Script phase which shows you what they all are.

Now, go back into MyApp, remove the reference to XMLRPC.framwork. Add back the version in the new location, which should be directly under build. You also need to clean up the FRAMEWORK_SEARCH_PATHS setting on the MyApp target for both Release and Debug configurations. Ooops. I wish I’d spotted my mistake earlier!

So now we’ve linked against the framework, and set up the header search path. To check the latter, add a new Objective-C class and add in:

#import <XMLRPC/XMLRPC.h>

A build of MyApp should succeed without error.

But there’s one more trick. We want to build the XMLRPC project as part of our own build. In order to do this, you need to drag XMLRPC.xcodeproj into MyApp.

Drag XMLRPC project file into MyApp

This should pop up the same sheet where you need to choose “Reference Type: Relative to Project.”

With that done, right-click on the MyApp target and choose Get Info. On the general tab, add XMLRPC as a direct dependency.

Add dependency on XMLRPC to MyApp

Now, when you build MyApp, you should see the XMLRPC project being built too. Even better, if you switch configurations, you should see the framework being built in the same configuration.

Build log from MyApp

In summary, the steps were:

  1. Modify the framework to support the same configurations as your project.
  2. Modify the framework to put the built artifact in a consistent location.
  3. Add the framework to your project (making sure to select “relative to project” and “add to target”).
  4. Add a reference to the framework’s project to your project.
  5. Add the target for the framework as a direct dependency of your target that needs it.

It may seem like a lot of effort, but it really only takes a few seconds. And now you’ve got the ability to pull in hundreds of wonderful open-source projects to make your app better!

Expanding Outline Views in Cocoa

Thanks to a lengthy commute last week, I’ve been making a toy in Cocoa. It reads an URL, parses some XML and displays it in an NSOutlineView. Simple stuff, but it will hopefully make my life better at work, where I need to do this a fair bit.

By default, when I load the XML into the NSOutlineView, everything is closed up. So all you’re presented with is the root element. I’d like to expand that so it automatically includes all children of the root element. Nice and simple—there’s an expandItem: method.

Except that when I call it from the action that puts the XML into the NSOutlineView, it doesn’t work. Bugger.

After instrumenting my XML data source, I can see that nothing is really happening until after my action. My suspicion is that the NSOutlineView isn’t realising that it has any data until after the first call to display.

I tested this by hooking up the call to expandItem into a secondary action (on another button). And it works great.

So, I need a way to say “call this code back in the next idle period”. And this is where I start to get upset that Objective-C doesn’t have closures.

How to execute code soon isn’t easily determined from the apple docs. My guess is that you use an NSTimer with a very small NSTimeInterval . Let’s try that…

  NSTimer *idle = [NSTimer scheduledTimerWithTimeInterval:0.0
                                                   target:self
                                                 selector:@selector(expandRoot)
                                                 userInfo:nil
                                                  repeats:NO];
  [[NSRunLoop currentRunLoop] addTimer:idle forMode:NSDefaultRunLoopMode];

Well, it works. But! Further investigation finally reveals Deferring the Execution of Operations. This suggests that I should use an NSNotification instead, but posted with a NSPostWhenIdle flag. This means getting involved with the cocoa notifications system

The code now ends up looking like this:

  - (void)awakeFromNib
  {
    // Listen out for notification's we've posted to ourselves.
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(expandRoot:)
                                                 name:@"expandRoot"
                                               object:nil];
  }

  -(IBAction)fetch: (id)sender
  {
    // …
    NSNotification* todo = [NSNotification notificationWithName:@"expandRoot"
                                                         object:self];
    [[NSNotificationQueue defaultQueue] enqueueNotification:todo
                                               postingStyle:NSPostWhenIdle];
  }

  - (void)expandRoot:(NSNotification *)notification
  {
    [outlineView expandItem:[[outlineViewDataSource doc] rootElement]];
  }

Which is quite a bit more code. But it feels more robust doing it this way.

The big take away from all this is how difficult it is to use a non-Open-Source framework. If I had the source to Cocoa, I’d be able to look inside and see what I needed to do simply and quickly. Instead, it took me three train journeys. But there’s still enough to like in Cocoa that I intend to carry on.

Unit Testing falsehoods

My latest fad is looking at developing Mac apps (in Cocoa). Since the Leopard upgrade, Objective-C 2.0 has Garbage Collection. Congratulations Apple, you’ve lifted it out of the dark ages.

So, I’ve been trying to read up bits in ADC, but my time is limited. This means I turn to podcasts like Late Night Cocoa which I can listen to during my commute.

Today, I was listening to the latest Mac Developer Roundtable, Testing Testing Testing. Neat, I wondered how to do unit testing in Cocoa.

Sadly, the discussion was like asking blind people to critique a painting. None of the participants (save the host, Scotty) actually knew what Unit Testing was, or had ever done any. It was the most ill informed discussion I’ve had the misfortune to hear in a long while.

“asserts are just another form of unit testing.”

“Well, I know my code, so I don’t have to bother with unit testing.”

“Unit testing doesn’t give any value.”

(all paraphrased, but it’s the gist of things).

It’s weird, sort of like jumping back 10 years in time. Like the whole agile thing never happened.

Now, I completely accept that XCode might have terrible support for unit testing. It’s possible, I have’t got that far yet. Likewise, OCUnit might be hard to use. But that doesn’t negate the value of knowing that you’ve fixed something and don’t have to go back to it.

This is particularly surprising, given the high quality of what I’ve seen in Cocoa so far. Apple is big on design patterns. In particular, MVC plays a huge rôle in Cocoa apps. Controllers and Views might well be hard to test, because they’re part of the GUI. But your Model (which is the core of your application) should really be amenable to testing.

I really hope that the rest of the Mac development community isn’t so stuck in the dark ages.