Sorting without NSArray controller

what code needs to be altered to make SpeakLine or A version of the toDoList tableview work in this case?
I can’t seem to get the swift [String] Arrays to work with the NSArrays.
I also built a simple tableView project with strings of names to test this code but I run into the same problem.

in order for the tableview to send the call for the function “sortedArrayUsingDescriptors…”, In the tableViews column attributes, I assigned the sort key to “key” and the selector to caseInsensitiveCompare: is that correct?
thanks,
a bit confused here

You are on the right track with the “caseInsensitiveCompare:” selector. Can you be more descriptive about the problems you’re running into with Swift string arrays vs NSArray? What kinds of errors are you seeing?

Hello
I have the same problem

In the optional delegate, function SortDescriptorDidChange is not called till I change the table colum filling the sort descriptor:
Sort key = key // ??? What is the key for the swift array
sort description = caseInsensitiveCompare:
Order: Ascending

Making dynamic the swift array voices doesn’t solve the problem for the Kvc compliant

The problem is this:

2015-05-12 09:52:44.921 SpeakLine[1301:303015] [<__NSCFString 0x618000076700> valueForUndefinedKey:]: this class is not key value coding-compliant for the key key.
2015-05-12 09:52:44.923 SpeakLine[1301:303015] (
	0   CoreFoundation                      0x00007fff9188e03c __exceptionPreprocess + 172
	1   libobjc.A.dylib                     0x00007fff89edc76e objc_exception_throw + 43
	2   CoreFoundation                      0x00007fff9188dbd9 -[NSException raise] + 9
	3   Foundation                          0x00007fff91c8bcc5 -[NSObject(NSKeyValueCoding) valueForUndefinedKey:] + 226
	4   Foundation                          0x00007fff91b60c3b -[NSObject(NSKeyValueCoding) valueForKey:] + 385
	5   Foundation                          0x00007fff91b73951 -[NSObject(NSKeyValueCoding) valueForKeyPath:] + 324
	6   Foundation                          0x00007fff91b93baa _sortedObjectsUsingDescriptors + 390
	7   Foundation                          0x00007fff91b939cb -[NSArray(NSKeyValueSorting) sortedArrayUsingDescriptors:] + 521
	8   SpeakLine                           0x000000010000426c _TFC9SpeakLine20MainWindowController9tableViewfS0_FTCSo11NSTableView24sortDescriptorsDidChangeGSaPSs9AnyObject___T_ + 316
	9   SpeakLine                           0x00000001000043ff _TToFC9SpeakLine20MainWindowController9tableViewfS0_FTCSo11NSTableView24sortDescriptorsDidChangeGSaPSs9AnyObject___T_ + 95
	10  AppKit                              0x00007fff8bfb5677 -[NSTableView setSortDescriptors:] + 264
	11  AppKit                              0x00007fff8c3a0b78 -[NSTableView _changeSortDescriptorsForClickOnColumn:] + 388
	12  AppKit                              0x00007fff8c389c45 -[NSTableHeaderView _trackAndModifySelectionWithEvent:onColumn:stopOnReorderGesture:] + 1046
	13  AppKit                              0x00007fff8c38c9b2 -[NSTableHeaderView mouseDown:] + 434
	14  AppKit                              0x00007fff8c4592fc -[NSWindow _reallySendEvent:isDelayedEvent:] + 14125
	15  AppKit                              0x00007fff8bde8d76 -[NSWindow sendEvent:] + 470
	16  AppKit                              0x00007fff8bde5312 -[NSApplication sendEvent:] + 2504
	17  AppKit                              0x00007fff8bd0ec68 -[NSApplication run] + 711
	18  AppKit                              0x00007fff8bc8b354 NSApplicationMain + 1832
	19  SpeakLine                           0x0000000100010b9d main + 109
	20  libdyld.dylib                       0x00007fff971c65c9 start + 1
)

Here the list of my code

//
//  MainWindowController.swift
//  SpeakLine
//
//  Created by Giancarlo Giaretta on 08/05/15.
//  Copyright (c) 2015 Giancarlo Giaretta. All rights reserved.
//

import Cocoa
//dichiaro il controller come aderente al protocollo
class MainWindowController: NSWindowController, NSSpeechSynthesizerDelegate, NSWindowDelegate, NSTableViewDataSource, NSTableViewDelegate {
    
    @IBOutlet weak var textField: NSTextField!
    @IBOutlet weak var speakButton: NSButton!
    @IBOutlet weak var stopButton: NSButton!
    @IBOutlet weak var tableView: NSTableView!
    
    let speechSynth = NSSpeechSynthesizer()
    
    //riceve dalla classe un array delle voci in formato severse domain
    //il dynamic mi serve per rendere l'assay KVC per l'ordinamento
    dynamic var voices = NSSpeechSynthesizer.availableVoices() as! [String]
    
    var isStarted:Bool = false {
        didSet {
            updateButtons()
        }
    }
    
    override var windowNibName: String {
        return "MainWindowController"
    }

    override func windowDidLoad() {
        super.windowDidLoad()
        updateButtons()
        //setto l'istanza come delegato e queta è una referenza weak
        speechSynth.delegate = self
        println(voices)
        for voice in voices {
            println(voiceNameForIdentifier(voice)!)
        }
        let defaultVoice = NSSpeechSynthesizer.defaultVoice()
        if let defaultRaw = find(voices, defaultVoice){
            let indices = NSIndexSet(index: defaultRaw)
            tableView.selectRowIndexes(indices, byExtendingSelection: false)
            tableView.scrollRowToVisible(defaultRaw)
        }

        // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
    }
    
    
    // MARK: Action Methods
    
    @IBAction func speakIt(sender: NSButton){
        let string = textField.stringValue
        if string.isEmpty {
            println("la string del \(textField) è vuota")
        } else {
            println("la string è \"\(string)")
            speechSynth.startSpeakingString(string)
            isStarted = true
        }
    }
    
    @IBAction func stopIt(sender: NSButton){
        println("cliccato il bottone Stop")
        speechSynth.stopSpeaking()
    }
    
    func updateButtons(){
        if isStarted {
            speakButton.enabled = false
            stopButton.enabled = true
        }else {
            stopButton.enabled = false
            speakButton.enabled = true
        }
    }
    //ritorna la voce in formato semplice di un identificativo di voce in formato reverse domain
    func voiceNameForIdentifier(identifier: String) -> String?{
        if let attributes = NSSpeechSynthesizer.attributesForVoice(identifier){
            return attributes[NSVoiceName] as? String
        } else {
            return nil
        }
    }
    
    // MARK: - NSSpeechSynthesizerDelegate
    
    func speechSynthesizer(sender: NSSpeechSynthesizer, didFinishSpeaking finishedSpeaking: Bool) {
        isStarted = false
        println("finishedSpeaking= \(finishedSpeaking)")
    }
    
    // MARK: - nsWindowDelegate
    
    func windowShouldClose(sender: AnyObject) -> Bool {
        //impedisce la chiusura della finestra se lo speech parla
        //non ha bsogno di settare il delegato in quanto la proprietà del delegato di window
        //è gia dettata nel File's Owner
        return !isStarted
    }
    
    // MARK: - NSTableViewDataSource
    
    func numberOfRowsInTableView(tableView: NSTableView) -> Int {
        return voices.count
    }
    //restituisce un oggetto stringa alla Table View per la cella
    //con il binding viene ripreso il Value dal TextField
    func tableView(tableView: NSTableView, objectValueForTableColumn tableColumn: NSTableColumn?, row: Int) -> AnyObject? {
        let voice = voices[row]
        let voiceName = voiceNameForIdentifier(voice)
        return voiceName
    }
    
    func tableView(tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [AnyObject]) {
        //prendo un descrittore della tabella
        let sortDescriptors = tableView.sortDescriptors
        println("clikkato")
        //definisco l'array di tipo NSArray per avere il metodo per ordinare in base al desciptor
        let objectsArray = voices as NSArray
        //Uso il metodo per ordinare l'array'
        let sortedObjects = objectsArray.sortedArrayUsingDescriptors(sortDescriptors)
        //assegno a voices l'array ordinato
        voices = sortedObjects as! [String]
        //ricarico la tabella
        tableView.reloadData()
    }

    
    // MARK: - NSTableViewDelegate
    
    func tableViewSelectionDidChange(notification: NSNotification) {
        let row = tableView.selectedRow
        
        if row == -1 {
            speechSynth.setVoice(nil)
            return
        }
        let voice = voices[row]
            speechSynth.setVoice(voice)
    }

There is a little bit of a trick when using sort descriptors to sort an array of strings. Sort descriptors are more intended for dealing with an array of data model objects where the key corresponds to one of the properties of that object. In the case of sorting an array of strings, what you want is to compare on the object itself, so you can use an empty key or, if you prefer, “self”.

let strings = ["B", "A", "c"]

let sortDescriptor = NSSortDescriptor(key: "self", ascending: true, selector: Selector("caseInsensitiveCompare:"))
let nsArrayOfStrings = strings as NSArray
let sortedStrings = nsArrayOfStrings.sortedArrayUsingDescriptors([sortDescriptor])

Arrgh ! it was so simple …
self is the receiving tableView of the click and then it call the delegate mainWindowController for the method
It was in front of my eyes but I didn’t see it. The interface build of xib file is easy but hides the things
Thank you