23rd Aug 2006

Core Data, Bindings, and Sorting in an NSTableView: The Easy Way

So I’m working on a little Core Data based application that you will hear more about in the future. In it, I have an NSTableView whose coulmn headers are bound to an NSArrayController, which in turn is bound to the managedObjectContext to get all my spiffy data.

Problem #1: Core Data doesn’t do sorting. Every time the app is launched, the data in the table appears randomly. Having it appear sorted on launch was actually really simple. Here’s the solution:

1. Implement a KVC NSArray object in your controller or delegate object, and have it return an NSArray with the default sortDescriptor (here I am sorting by a ‘date’ property):

- (NSArray *)sortDescriptor
{
	if(sortDescriptor == nil){
		sortDescriptor = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO]];
		}

	return sortDescriptor;
}

- (void)setSortDescriptor:(NSArray *)newSortDescriptor
{
	sortDescriptor = newSortDescriptor;
}

2. In Interface Builder, bind the sortDescriptors Controller Content Parameter to your controller or delegate object, and set the Model Key Path to whatever you called your NSArray of sort descriptors (in my case, sortDescriptor).

That’s it! It wasn’t as intuitive as I originally thought, but it certainly seems pretty clean to me.

BUT WAIT! We have a new problem now.

Problem #2: Objects that are inserted or changed in the table aren’t sorted properly. Fixing this problem was a little trickier, but I found a solution to it at CocoaDev’s RearrangeObjects page. Here’s my little implementation of it (although original credit should go to JediKnil):

1. Register to hear the NSManagedObjectContextObjectsDidChangeNotification, preferably somewhere in your app controller’s awakeFromNib method.

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(objectsDidChange:) name:NSManagedObjectContextObjectsDidChangeNotification object:[self managedObjectContext]];

2. Next, we implement the objectsDidChange: method:

- (void)objectsDidChange:(NSNotification *)note
{
       [myArrayController rearrangeObjects];
}

This forces the table to check it’s arrangement every time any object is changed, added, or deleted. Depending on your purposes, you may want to use JediKnil’s method which checks for certain properties changes, and avoids rearranging if unneeded.

That’s it! It took me a while to figure this out and I saw others were having the same problems else where and never really got answers, so hopefully this is useful to someone. Good luck!

Posted by Posted by patrick under Filed under bindings, code, coredata, how-to, sorting Comments 1 Comment »

15th Aug 2006

Hacking the Nike+iPod

I recently got a Nike+iPod sport kit and shoes. They are really damn cool. It does what it is meant to do quite well (tracking your run and giving you all kinds of fun motivating statistics) but I had always wondered how it recorded the information, and if there was anything else fun I could get it to do.

Luckily for everyone, Apple and nike chose to record this data as clean XML. Here’s what a workout file looks like:

<?xml version="1.0" encoding="UTF-8"?>
<sportsData><vers>1</vers>
<runSummary><workoutName>Basic</workoutName>
<time>2006-08-13T00:54:49-04:00</time>
<duration>1716812</duration>
<durationString>28:36</durationString>
<distance unit="km">4.3527</distance>
<distanceString>4.35 km</distanceString>
<pace>6:34 min/km</pace>
<calories>355</calories>
<battery></battery>
<playlistList><playlist><playlistName>Running</playlistName>
</playlist>
</playlistList>
<stepCounts><walkBegin>124</walkBegin>
<walkEnd>1316</walkEnd>
<runBegin>98</runBegin>
<runEnd>3028</runEnd>
</stepCounts>
</runSummary>
<template><templateID>8D495DCE</templateID>
<templateName>Basic</templateName>
</template>
<goal type="" value="" unit=""></goal>
<userInfo><empedID>5C6284WFVSX</empedID>
<weight>79.4</weight>
<device>iPod</device>
<calibration>000000004170000001fe00230000000041f0000004a1000000002b0000000000</calibration>
</userInfo>
<startTime>2006-08-13T00:54:49-04:00</startTime>
<snapShotList snapShotType="userClick"><snapShot event="onDemandVP"><duration>313248</duration>
<distance>0.92</distance>
</snapShot>
<snapShot event="onDemandVP"><duration>528706</duration>
<distance>1.548</distance>
</snapShot>
<snapShot event="onDemandVP"><duration>755721</duration>
<distance>2.222</distance>
</snapShot>
<snapShot event="onDemandVP"><duration>790638</duration>
<distance>2.284</distance>
</snapShot>
<snapShot event="onDemandVP"><duration>1066793</duration>
<distance>2.714</distance>
</snapShot>
<snapShot event="onDemandVP"><duration>1277388</duration>
<distance>3.341</distance>
</snapShot>
<snapShot event="onDemandVP"><duration>1410509</duration>
<distance>3.552</distance>
</snapShot>
<snapShot event="powerSong"><duration>1412404</duration>
<distance>3.554</distance>
</snapShot>
<snapShot event="stop"><duration>1716780</duration>
<distance>4.352</distance>
</snapShot>
</snapShotList>
<snapShotList snapShotType="kmSplit"><snapShot><duration>339859</duration>
<distance>1.0</distance>
</snapShot>
<snapShot><duration>677423</duration>
<distance>2.001</distance>
</snapShot>
<snapShot><duration>1168834</duration>
<distance>3.0</distance>
</snapShot>
<snapShot><duration>1558960</duration>
<distance>4.0</distance>
</snapShot>
</snapShotList>
<snapShotList snapShotType="mileSplit"><snapShot><duration>549808</duration>
<distance>1.611</distance>
</snapShot>
<snapShot><duration>1236915</duration>
<distance>3.219</distance>
</snapShot>
</snapShotList>
<extendedDataList><extendedData dataType="distance" intervalType="time" intervalUnit="s" intervalValue="10">0.0, 0.0201, 0.0331, 0.0608, 0.098, 0.13, 0.1586, 0.1899, 0.2219, 0.2542, 0.2858, 0.3174, 0.3447, 0.3745, 0.4045, 0.4323, 0.467, 0.4948, 0.526, 0.5579, 0.586, 0.6159, 0.6486, 0.6789, 0.706, 0.7344, 0.7678, 0.795, 0.8255, 0.8592, 0.8852, 0.9146, 0.9445, 0.9711, 1.0004, 1.0296, 1.0563, 1.0882, 1.1148, 1.1447, 1.1753, 1.2036, 1.2338, 1.2632, 1.2934, 1.3219, 1.3515, 1.3811, 1.4105, 1.4401, 1.4656, 1.4948, 1.5246, 1.5509, 1.5808, 1.6115, 1.6395, 1.6729, 1.7034, 1.7304, 1.7604, 1.7922, 1.8245, 1.8536, 1.8847, 1.9164, 1.9476, 1.9793, 2.0107, 2.0425, 2.0697, 2.1003, 2.1317, 2.1616, 2.1865, 2.2137, 2.2369, 2.2516, 2.2664, 2.2846, 2.2988, 2.3148, 2.3308, 2.3471, 2.3633, 2.3775, 2.3936, 2.41, 2.4263, 2.4407, 2.4581, 2.4716, 2.4872, 2.5027, 2.5192, 2.5334, 2.5487, 2.5662, 2.5804, 2.5962, 2.6108, 2.6263, 2.6424, 2.6584, 2.6744, 2.6902, 2.704, 2.7188, 2.7341, 2.75, 2.7794, 2.8115, 2.8469, 2.8768, 2.9089, 2.9377, 2.9728, 3.0067, 3.0369, 3.0706, 3.102, 3.1347, 3.1682, 3.2005, 3.2293, 3.2613, 3.2906, 3.3215, 3.3471, 3.3636, 3.3782, 3.3931, 3.411, 3.427, 3.4416, 3.4579, 3.4742, 3.4888, 3.5074, 3.5213, 3.5383, 3.5518, 3.5634, 3.5822, 3.5978, 3.6106, 3.6486, 3.6933, 3.7372, 3.7769, 3.8201, 3.8626, 3.9049, 3.9381, 3.9691, 3.986, 4.0022, 4.0185, 4.0331, 4.0489, 4.0654, 4.0831, 4.098, 4.1143, 4.1303, 4.1463, 4.176, 4.2112, 4.2456, 4.2796, 4.3102, 4.3404</extendedData>
</extendedDataList>
</sportsData>

As you can see, the extendedData tag holds the real meat of the workout: the distance ran (in kilometers, since that’s how I set mine up) recorded every 10 seconds. We also get interesting snapShot items, that tell us the exact moment, to 1/1000 of a second, when we hit certain kilometer or mile milestones, or when the user hit the Voice Feedback button (the “onDemandVP” event).

You can also see, closer to the top, basic workout info such as how many calories burned duration, distance, average pace, etc.

Some things of interest include the stepCounts tag, which I guess counts steps, but isn’t used at all in the Nike+iPod interface.

It’s cool that this data is totally open and free to be hacked upon, although I’m not quite sure what I would use if for just yet, as the Nike+iPod web app seems to handle pretty much all my needs thus far. It’s nice to know that should the Nike+ service ever die, writing your own desktop app (that is much more precise and feature-ful) would not be difficult.

Hopefully this will be of use to someone or even just the curious like me.

Posted by Posted by patrick under Filed under apple, hacking, nike+ipod Comments 3 Comments »

31st Jul 2006

My WWDC Wishlist

There are a bazillion rumours floating around on the internet about what is going to be announced at WWDC next week. Everything from an Apple cell phone to Core 2 Duo “Mac Pro” machines, to the “iTunes Movie Store” and more. Hardware always seems to attract the rumour-mongers, but after getting more involved with programming for OS X I am finding myself much more interested in the obvious: Leopard, the next generation of Mac OS X. This might also be because I recently bought a MacBook, and thus don’t and won’t really care about hardware for a while.

There’s a lot of big, big things Apple could do Leopard, since they stated they want to slow down major releases. In my mind, slower releases is akin to having bigger major releases. That said, I’m thinking Leopard is going to pretty big and special so that it has a longer life-span.

Here’s my short, crazy unrealistic wish-list:

  • Xcode 3 will be open-sourced, and will be able to benefit from the community just like WebKit already has.
  • Leopard will FTFF (”Fix the Fucking Finder”, for the uninitiated) but it will go further than that. The entire OS will receive an slight appearance overhaul, and improve the oh-so-elusive UI consistency that is lacking in Tiger.
  • Part of the new UI will have BeOS style window title bars. Okay, I know this isn’t likely… but they are just so much nicer and more efficient.
  • Quartz 2D Extreme will be turned on. And it will kick ass.
  • Leopard Light - Apple will offer a stripped down Mac OS X that can run nicely on older/smaller systems.

Posted by Posted by patrick under Filed under apple, me, wwdc Comments No Comments »

12th Jul 2006

How-To: Use SSH Keys and SSHKeychain for Passwordless Logins

There’s a few tutorials floating around on the internet on how to use ssh keys to login to your servers without having to type your password each time. It’s a very useful thing to do but sadly none of these tutorials are Mac OS X specific. Therefore, I thought I’d help out my Mac OS X native friends (Hi James!) and provide one that leverages the value of SSH keys using SSHKeychain.

The whole process is pretty simple: You create your SSH keys using ssh-keygen on your home computer, then upload your public key to the servers you wish you use passwordlessly, set up SSHKeychain, and you are golden. Let’s get to it.

To create your SSH keys use the following command and follow the on screen instructions, although you can leave the file name blank, since the defaults are fine:

ssh-keygen -t dsa

I can’t recommend using a blank password, because hey, it just seems dodgy. After you do that, two new files have been created in ~/.ssh/, id_dsa and id_dsa.pub. As you probably guessed, id_dsa.pub is your public key. Upload it to the servers you want to access it using scp, and place it in ~.ssh/authorized_keys2:

scp ~/.ssh/id_dsa.pub yourserver.com:.ssh/authorized_keys2

Since this is probably your first time setting up ssh keys, that file most likely won’t already exist, although it would probably be worthwhile to check if it does, and simply append your id_dsa.pub file to it if necessary.

Special note: My awesome web host, nearlyfreespeech.net, has a different method of handling public SSH keys. I needed to send them my public key in a service request for it to be added to their private database, which was no problem, but different than usual. If your having trouble logging in without a password, try asking your server guys what’s up first.

Now usually what we would have to do is start ssh-agent (which handles our key exchanges for us), tell it to add our new keys, and then use the shell it provides us with. Although this could be added to your shell login file, there is a much easier and more convienent way in Mac OS X.

Enter SSHKeychain. This app basically loads ssh-agent for you all the time, so you don’t have to worry about it, as well as other nice little things. And it’s free. Go OSS! Install this app (download, mount, copy, trash the dmg, you know the drill), set up the prefs (I have it appear only in the menubar for dock cleanliness), and go into the environmental tab and turn on “Manage global environment variables”. Log out and log back in, and you should now be able to ssh into your without being prompted for a password! Just keep that id_dsa file nice and secure, eh? ;)

Next up, I’m going to cover how to use SSHKeychain to setup and use SSH tunnels.

This is my first tutorial (or even real article) on this blog, so if you have any comments, suggestions, or corrections, please feel free to email me at patrick @ this domain.

Posted by Posted by patrick under Filed under how-to Comments 3 Comments »

07th May 2006

Back In… Blogging.

So, I started up a blog again. You’re looking at it. It’s pretty snazzy, I have to say. Wordpress (and the associated K2 bundle) have come a long way since I first touched them years ago. I swore off blogging a long time ago, so you might be wondering – like I was – what the hell I’m doing with yet another blog, contributing to mindless, useless mess that has become… “The Blogosphere”.

Well, good call. I’m glad you are concerned with the state of the internet as well. There are way too many people who just don’t seem to care, and feel that it is somehow useful (even though it isn’t, at all), to post about how cute their cat is or what they ate for lunch. So to answer the question, what is it that I’m doing here? Well, I thought it would be useful to have this site so that I can document and contribute my discoveries and knowledge to the growing Mac OS X developer community. It’s somewhat of a specialized field, and sometimes it can be hard to find the information you want, so if it’s not already out there, my goal is going to be to try and put it out there.

I’m just a student, and I’m learning constantly, as are most devs, so I won’t claim to know everything or try to answer every question. I’m going to post when I stumble across interesting information, and do things as I go.

I’ve set up a bunch of useful links to the best OS X Dev resources on the internet, and hope to publish my first article soon.

Hopefully this site will end up proving useful to my fellow OS X developers. Wish me luck, here I go.

Posted by Posted by patrick under Filed under me, meta Comments No Comments »