Challenge solution: SPOILER

The challenges thus far in the book have been somewhat more involved. But I was surprised to see this one so easy.

Select the name column in the xib file.
Select the attributes inspector tab.
Change the sort key to "name.length"
Change the selector to “compare:”

That’s it.

Doing this, I get this error,

Error setting value for key path sortDescriptors of object <NSArrayController: 0x6000001c03c0>[object class: RaiseMan.Employee, number of selected objects: 1] (from bound object <NSTableView: 0x102010a50>): [<RaiseMan.Employee 0x6080000579a0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key compare:. 2015-08-18 12:13:22.030 RaiseMan[1717:89931] ( 0 CoreFoundation 0x00007fff9387c03c __exceptionPreprocess + 172 1 libobjc.A.dylib 0x00007fff8810f76e objc_exception_throw + 43 2 CoreFoundation 0x00007fff9387be1a +[NSException raise:format:arguments:] + 106 3 AppKit 0x00007fff89e40145 -[NSBinder _setValue:forKeyPath:ofObject:mode:validateImmediately:raisesForNotApplicableKeys:error:] + 841 4 AppKit 0x00007fff89e3fda3 -[NSBinder setValue:forBinding:error:] + 248 5 AppKit 0x00007fff89f14d59 -[NSTableBinder tableView:didChangeToSortDescriptors:] + 146 6 AppKit 0x00007fff89f14cb0 -[_NSBindingAdaptor tableView:didChangeToSortDescriptors:] + 153 7 AppKit 0x00007fff89e4b543 -[NSTableView setSortDescriptors:] + 228 8 AppKit 0x00007fff8a236b58 -[NSTableView _changeSortDescriptorsForClickOnColumn:] + 388 9 AppKit 0x00007fff8a21fc25 -[NSTableHeaderView _trackAndModifySelectionWithEvent:onColumn:stopOnReorderGesture:] + 1046 10 AppKit 0x00007fff8a222992 -[NSTableHeaderView mouseDown:] + 434 11 AppKit 0x00007fff8a2ef2dc -[NSWindow _reallySendEvent:isDelayedEvent:] + 14125 12 AppKit 0x00007fff89c7ec86 -[NSWindow sendEvent:] + 470 13 AppKit 0x00007fff89c7b212 -[NSApplication sendEvent:] + 2504 14 AppKit 0x00007fff89ba4b68 -[NSApplication run] + 711 15 AppKit 0x00007fff89b21244 NSApplicationMain + 1832 16 RaiseMan 0x000000010000557d main + 109 17 libdyld.dylib 0x00007fff930505c9 start + 1 18 ??? 0x0000000000000003 0x0 + 3 )

It says that my Employee class is not KVC compliant, but it is subclassed from NSObject

Never mind, I was putting the Key in the Selector place, and the Selector in the Key place! Doh!

Does anyone know how to do this in Swift 2? strings don’t have the length method anymore, and so I tried to use name.characters.count for the key and I got the following error:

RaiseMan[37786:9008958] Error setting value for key path sortDescriptors of object <NSArrayController: 0x6000001c04b0>[object class: RaiseMan.Employee, number of selected objects: 0] (from bound object <NSTableView: 0x101417d60>): [<NSTaggedPointerString 0x626125> valueForUndefinedKey:]: this class is not key value coding-compliant for the key characters.
2015-09-12 13:36:42.716 RaiseMan[37786:9008958] (
0 CoreFoundation 0x00007fff8b1d203c __exceptionPreprocess + 172
1 libobjc.A.dylib 0x00007fff89edf76e objc_exception_throw + 43
2 CoreFoundation 0x00007fff8b1d1e1a +[NSException raise:format:arguments:] + 106
3 AppKit 0x00007fff9318a145 -[NSBinder _setValue:forKeyPath:ofObject:mode:validateImmediately:raisesForNotApplicableKeys:error:] + 841
4 AppKit 0x00007fff93189da3 -[NSBinder setValue:forBinding:error:] + 248
5 AppKit 0x00007fff9325ed59 -[NSTableBinder tableView:didChangeToSortDescriptors:] + 146
6 AppKit 0x00007fff9325ecb0 -[_NSBindingAdaptor tableView:didChangeToSortDescriptors:] + 153
7 AppKit 0x00007fff93195543 -[NSTableView setSortDescriptors:] + 228
8 AppKit 0x00007fff93580b58 -[NSTableView _changeSortDescriptorsForClickOnColumn:] + 388
9 AppKit 0x00007fff93569c25 -[NSTableHeaderView _trackAndModifySelectionWithEvent:onColumn:stopOnReorderGesture:] + 1046
10 AppKit 0x00007fff9356c992 -[NSTableHeaderView mouseDown:] + 434
11 AppKit 0x00007fff936392dc -[NSWindow _reallySendEvent:isDelayedEvent:] + 14125
12 AppKit 0x00007fff92fc8c86 -[NSWindow sendEvent:] + 470
13 AppKit 0x00007fff92fc5212 -[NSApplication sendEvent:] + 2504
14 AppKit 0x00007fff92eeeb68 -[NSApplication run] + 711
15 AppKit 0x00007fff92e6b244 NSApplicationMain + 1832
16 RaiseMan 0x0000000100002e07 main + 87
17 libdyld.dylib 0x00007fff8ae9c5c9 start + 1
18 ??? 0x0000000000000003 0x0 + 3
)

An update to the book and sample code covering Swift 2.0 has been published. See the post here on the forums about it: http://forums.bignerdranch.com/viewtopic.php?f=512&t=10109.

Unfortunately, the update doesn’t seem to cover any changes required to complete the challenges.

Even more bizarrely, setting name.length as the sort key is working for me in Xcode 7.1, even though it doesn’t let me call length on a String in a playground!

No idea what’s going on there…

I wonder if .length still works because that is still a valid call on an NSString. Perhaps these values are treated as NSString somewhere between the Employee class and the Table View.

Just blasting through a .length didn’t work for me. I’m wondering if in your class definition you actually have it defined as var name : NSString? ="" or something. Anyway, I decided to just make a computed property, which worked, though I have no idea if it’s optimal:

var nameLength : Int
    {
        get
        {
            let retVal = name?.characters.count ?? 0
            return retVal
        }
    }

For what it’s worth… I’m running Xcode 7.2 and “name.length” for the Sort Key worked fine; however, I’m not sure if it’s been said already but you also have to change the Selector from “caseInsensitiveCompare:” (for actual names) to simply “compare:” (for the numeric values returned by length). This may have been obvious and done by everyone experiencing issues previously, but I just wanted to explicitly state it.

I changed the employee model’s name property to be String instead of an optional String. Oddly, using the key path name.length still worked. It must be toll-free bridging to an NSString for me, because a Swift String does not have that selector. But it finally works!