Saturday, November 11, 2006

[Tutorial] Lets get sorting

Well I am back people! This whole past couple weeks have just been crazy at work and in combination with hunting bugs in my first early Beta of AssignmentTracker X I haven't had much time for this blog lately, but now I am back and things have settled down and I am already full of stuff to post. Hey I'm just a student people, give me a break. Well for today I am gonna post 2 things that made my own LicenseKeeper app a little bit better. (1)I liked that I could easily store all my serial numbers, but I wanted them sorted by default (2)When I resized the columns I wanted the app to keep track of the length of them Let's get sorting! Like many things in life Core Data has a slight trade-off in that you now have automatic data persistence, but the data is not sorted. If you create a Core Data app right now, like creating a simple table that displays entities with 1 attribute (lets say a name) and create a few entities without telling the array controller to sort them and then quit and reopen the app a few times, the order of the entities will be almost random every time. So people new to Core Data then ask how do we keep this data sorted? Well Apples Documentations spells it out like so “ Objects in a persistent store are unordered. Typically you should impose order at the controller or view layer, based on an attribute such as creation date. If there is order inherent in your data, you need to explicitly model that.” In other words it's up to you to sort your data. So all I did was create a controller class I called LKAppController with an outlet to the NSArrayController. Here is LSAppController.h.

#import < cocoa/cocoa.h > @interface LKAppController : NSObject { IBOutlet NSArrayController *licensesController; } @end
Then I instantiated the class in Interface Builder and connected the outlet to the NSArrayController. And to sort the data I created a NSSortDescriptor and told the array controller to sort the objects it has with that sort descriptor in the awakeFromNib method. Here is LKAppController.m.
#import "LKAppController.h" @implementation LKAppController - (void)awakeFromNib { NSSortDescriptor * sd = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]; [licensesController setSortDescriptors:[NSArray arrayWithObject:sd]]; [sd release]; } @end
I should state that this is not Core Data specific, in fact this method can be applied to any array controller in Cocoa. Now this is easy because in this instance we have a bunch of objects that we just want to sort by their name. I suggest that if you have to have objects in some specific order for something like a Source list (where we might want some static items at the top then user items at the bottom of the list) that you create an attribute and call it something like “position” that's an int sort it like that or use some other attribute or method you like, the point is you must create the means to sort the way you want. The only area where it may get difficult to auto sort items is in NSOutlineViews in which case you may find this ( ) to be of interest. Keeping track of column length So now we have our data sorted by default I wanted to do something nice for myself and make the app remember the length of all the columns when I resized them so I could at any time change them to my hearts content. Many people don't realize you can do this, but if you poke around in the Cocoa Bindings you can bind the length as well as the minimum length and max length of the columns to an entity or in this case (to make things simple) to the preferences. So all you need to do is select the table column and go to the Bindings option in the IB Inspector. Select the width attribute. For this we'll bind to Shared User Defaults (once you select this you should see the “Shared Defaults” controller appear in the instances tab), with the controller key “values” and model key path “nameColumnHeaderWidth” for the name column. Repeat the process for each additional column (giving a unique name for each model key path) and now your app will remember the length of each column as you drag them! It's the nice little stuff like this that you do that your users will really appreciate when you put out your app.


Tony Jensen said...

Thank you for the tutorials you have written so far.

You created them at a basic level which has allowed me to experiment with things like having the app remember the window height and width as well as remembering the column widths.

I have signed up to your RSS feed and am waiting anxiously for more tutorials.

B Gupta said...

Thank you for a simple and beautiful tutorial! As a beginner writing Cocoa applications I look forward to more tips like these.