Wednesday, August 22, 2007

All Out Of Sorts

I realize that it has been a while since my last post. Numerous reasons for this, including but not limited to: 1) I actually haven't done very much programming lately, and 2) what I have done has not produced much in the way of results. It's been a frustrating week or two.

Given my previous couple of postings on Model-View-Controller, I decided to rethink my mileage program structure. I originally decided that what I had worked, so I should just leave it alone. (hat tip to Wil Shipley) Then I decided that what I had didn't work, so I branched off in several directions on semi-related topics, and more or less broke the program. I played around with NSNumber and NSDecimalNumber for reasons I might go into in a later posting, and ultimately did not achieve what I wanted. Gave up on that, put the basic structure back in place, then rethought my classes.

My mileage program has a pretty basic Model class called Tank. It has methods for the kinds of things you might expect...gallons, odometer, etc. I have a user interface that contains a table View class that is supposed to display all of the gas tanks entered by the user. So I need an array somewhere. My first pass at this involved essentially a copy of a sample program provided by Mr. Nerd Ranch in his fantabulous book, so the array lived in a Controller class. And this worked really well. However, thinking ahead to what I eventually want this program to do, namely provide a summary report of all of the Car data entered, I realized that some other aspect of my program - probably a different Controller - would need to access this array. So either I need to enable one Controller to talk to another, or I need to make an additional Model class to contain the array. So I set out to create this new class, and then make the Controller talk to it.

I should probably clarify that my first pass didn't completely work. It mostly worked, but there were some issues with sorting the objects in the array and calculating some of the values those objects needed to contain. Long story short, the algorithm I was using was lacking, and it just in general didn't feel very object oriented-y. So I poked around in the NSArray and NSMutableArray documentation, and found some handy (or so I thought) sorting routines. Sweet! This lead to days of frustration as I couldn't find examples, and didn't feel that the documentation provided me enough information. I was hampered a bit by my own choices of how this program should work, and I must be a tad outside the norm because I sure didn't find any examples doing what I want to do.

Yes, I have a table view. Yes, it has column headers. No, I don't want the user to be able to re-sort the table by selecting those column headers. I want the table/array to be sorted by the odometer, period. So the handy little bindings approach means jack to me because I can't depend on a mouse click on a column header to determine when and how to sort. So, I need to force a re-sort and define the sort criteria programmatically. Read up on NSMutableArray, and found several sorting methods: sortUsingDescriptors:, sortUsingSelector:, and so on. Seemed straightforward enough to me, so I thought this would be easy. I thought that using a selector would be easiest, so I tried that route. I clearly was doing something wrong, because this never succeeded. I either got no sorting at all (other than data entry order), or it would invert the array, then add the new record to the beginning. Invert the array, then add the new record to the beginning. It. Was. Weird. (and. annoying.) So, let's try the descriptors. I can't count the number of times I repeated these steps:
1. Click on sortUsingDescriptors: in the documentation window.
2. Read all-too-brief description that really doesn't help, note the link to see NSSortDescriptor for more info.
3. Click on NSSortDescriptor
4. Enjoy the line that tells me I can use sort descriptors to sort an array, but do not find a handy example.
5. Muddle my way through something that ends up not working.

So, the purpose of this post tonight is to announce that I finally found an example, adapted it to my use, and it works. I would like to thank Arthur Clemens for this post. His example is working directly on the table view (I think), but I was able to tweak it to work on the array. For anyone else out there who may be trying to figure this out, HERE IS HOW TO SORT AN NSMUTABLEARRAY. (I'm going to type that a couple more times to improve the chances of this post being found on Google. Here is how to sort an NSMutableArray. Here is how to sort an NSMutableArray. Here is how to sort an NSMutableArray. Here is how to sort an NSMutableArray.)

NSSortDescriptor* sortDescriptor = [[[NSSortDescriptor alloc]
initWithKey: @"odometer" ascending: YES] autorelease];
[myMutableArray sortUsingDescriptors:[NSArray
arrayWithObject:sortDescriptor]];
It's beautiful, it works, and it does in 2 lines of code what my original took a good 20 to do. Thanks Arthur! Saved me many more days of frustration.

No comments: