More about sort descriptors

At the moment I use this code (provided by Ric) to sort a tableview based on a property, a numeric ID:

set sortCardsByID to current application's NSSortDescriptor's sortDescriptorWithKey_ascending_("cID",true)

It has worked well as long the cID was an integer, but this property was saved on a file using NSKeyedArchiver. When this cID comes back from the file using the unachiever, it is no more a numeric value. Whatever it is, it is sorted alphabetically, so you have

1, 12, 2 instead of 1, 2, 12.

The problem seems easy, but it’s not so simple. The methods of NSSortDescriptor don’t contain an integerAscending_ method, the comparators use blocks, which cannot be accessed in ASOC, so how to coerce this property to a NSInteger, or compare its intValue?

Trivial problem, I hope the solution is trivial as well.


Once again logging would help. Try logging a member of the array (or dictionary, I don’t know what you have now) to see what class cID is. I tried creating an array with numbers in it, archived it, unarchived it and logged the class of an object in the array and got NSCFNumber. When I sorted it using compare: it sorted properly.


I get NSCFString. Maybe I should coerce cID as integer before archieving. But when I write

        set cID of theCard  to (cID of theCard) as integer

all I get is:

2011-04-28 05:15:18.420 AutoText[4394:903] -[NSCFString objCType]: unrecognized selector sent to instance 0x7fff70de1a70

I could just cry.

If it’s an NSString, you have to coerce to a string and then to an integer.

But it seems to me you’re running around patching and patching, rather than going back to the source of the problem(s): in this case, if cID is an integer before archiving, you’re doing something wrong if it’s not when you unarchive it.

You were right, I forgot

on createNewCard(withID)
    set cID of cRecord to withID [b]as integer[/b]

I suppose Objective-C or a better typed language would have refused to compile if “subroutine createNewCard(withID : integer)” is called with a string. I was pretty sure withID was an integer. It was not.

So now, as long as I treat myCard’s cID as a string, it’s OK, but if I try set myCard’s cID to ((myCard’s cID)as string)as integer, I get the same error:

2011-04-28 11:12:41.721 AutoText[7380:903] -[NSCFString objCType]: unrecognized selector sent to instance 0x7fff70dd3650

[i]You are right, Shane, I pass 20% time programing and 80% time patching. I have re-written my app three times, each time with a more ASOC approach, because I’m learning by doing (I must admit my app was rather complex ten years ago, is’s not simpler nowadays, but I must admit that simple applications can effectively be written in a few hours).

But sometimes I can’t remove this feeling that with ASOC, I’m always trying to put a square into a circle. Couldn’t be just a bit more simple? It seems that Cocoa has been conceived to give all answers, but sometimes I forget the question.[/i]

I placed this where I load the file’s contents :

            set num to (theCard's cID) as integer
            theCard's setValue_forKey_(num, "cID")

then I opened and written down all my files, now the all have cID stored as integer – and correctly sorted.

Morality : in ASOC, never make assumptions on the type of a variable passed as parameter.

Thank you everybody. Problem solved.

It seems to me that there is still something wrong in your code if you have to coerce theCard’s cID to an integer – in the code you posted the other day to make at least one card, you called this method with createNewCard(1) :

on createNewCard(withID)
        set theFile to withID as string & ".atxt"
        tell application "Finder" to make new file at gCurrentFolder with properties {name:theFile, creator type:"ATXX"}
        set cName of cRecord to gProposedCardName
        current application's NSKeyedArchiver's archiveRootObject_toFile_(cRecord, theFile)
        my gCardController's addObject_({cID:withID,cRefCard: cRecord})

If you log the class of gCardController’s arrangedObjects()'s lastObject()'s valueForKey_(“cID”) you will get NSCFNumber not NSString, so if the value of cID was showing up as an NSString, you must have made it a string somewhere else in the code. Is the code above the only place where you create new cID’s?

If you pass a number (and by that I mean literal digits, 1,2,3,4, etc.) to a cocoa method it will be converted to an NSNumber, you shouldn’t have to coerce it first.


When the first file is (automatically) created, I call


but after this, the ID is defined by a property, gProposedID, which is bound to the interface. Somewhere on the way, maybe when I call

createNewCard(gProposedID) -- ouch, a property passed as parameter, that is gooood programming. but I wanted to get a parameter value here.
on createNewCard (withID)
set cID of cRecord to withID  -- no coercion seemed necessary, but it was. I got no error anyway.

cRecord was declared:

property cRecord : {cID:missing value,cName:"",cLongText:missing value,.

Is it possible that ASOC defaults missing value to NSString? Or is it another bug I left behind? I’ll look for it all over again.