NSTableView - лучшее решение для сортировки коллекции с помощью NSSortDescriptor - PullRequest
0 голосов
/ 08 февраля 2019

У меня есть NSTableView с 2 столбцами, связанными с массивом нестандартного типа (SelectedFiles) как File Name и File Path, после щелчка по заголовку я хочу отсортировать данные в порядке возрастания / убывания, я попыталсяэти коды с NSSortDescriptor:

class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        let fileNameSortDescriptor = NSSortDescriptor(key: "fileName", ascending: true, selector: #selector(NSString.localizedStandardCompare(_:)))
        tableView.tableColumns[0].sortDescriptorPrototype = fileNameSortDescriptor
        // other codes
    }
}

extension ViewController: NSTableViewDataSource, NSTableViewDelegate {

    func tableView(_ tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [NSSortDescriptor]) {
        let selectedFilesArray = NSMutableArray(array: selectedFiles)
        selectedFilesArray.sort(using: tableView.sortDescriptors) // Signal SIGABRT
        selectedFiles = selectedFilesArray as! [SelectedFiles]
        tableView.reloadData()
    }
}

Моя пользовательская коллекция для данных в табличном представлении:

struct SelectedFiles: CustomStringConvertible {
    let fileName: String
    let filePath: String
    var description: String {
        return "\(fileName) at path \(filePath)"
    }
}

var selectedFiles: [SelectedFiles] = []

Оказывается, это не работает вообще, IDK, если что-нибудьчто-то не так с моим кодом или я что-то упустил.

Итак, я пришел к такому неловкому решению:

var tableViewSortingOrder = ComparisonResult.orderedAscending

extension ViewController: NSTableViewDataSource, NSTableViewDelegate {

    func tableView(_ tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [NSSortDescriptor]) {
        switch tableViewSortingOrder {
        case .orderedAscending:
            tableViewSortingOrder = .orderedDescending
            selectedFiles.sort { (previous, next) -> Bool in
                return previous.fileName.compare(next.fileName) == tableViewSortingOrder
            }
        default:
            tableViewSortingOrder = .orderedAscending
            selectedFiles.sort { (previous, next) -> Bool in
                return previous.fileName.compare(next.fileName) == tableViewSortingOrder
        }
        tableView.reloadData()
    }
}

После того, как я перешел на это решение, оно работало отлично, так как быстро переключаетсямежду возрастающим / убывающим порядком.Но когда дело доходит до удаления объектов в коллекции, выдается Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value, когда я пытаюсь удалить несколько объектов как из коллекции, так и из таблицы с некоторыми конкретными файлами.

Итак, я подумаю, еслиЯ должен изменить способ достижения этой вещи сортировки заголовка, используя NSSortDescriptor (используйте старомодный способ, исправляя мой первый метод), чтобы избежать этой проблемы, я должен признать, что мой второй способ немногонеловко (больше похоже на план С).

Я прочитал несколько сообщений StackOverflow на эту тему, и я попробовал все их способы, особенно этот , я не использую CoreDataкакие его решения не подходят для моей ситуации.

Кто-нибудь может помочь указать путь, пожалуйста??

1 Ответ

0 голосов
/ 09 февраля 2019

Я прочитал руководство по NSTableView с сайта Apple для разработчиков и несколько других публикаций StackOverflow. Я нашел себе работоспособное решение для Swift 4:

Я установил sortDescriptorPrototype на fileNameSortDescriptor в viewDidLoad() подViewController class.

class ViewController: NSViewController {
    override func viewDidLoad()
        super.viewDidLoad()
        let fileNameSortDescriptor = NSSortDescriptor(key: "fileName", ascending: true, selector: #selector(NSString.localizedStandardCompare))
        let tableColumn = tableView.tableColumn(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "fileNameColumn"))!
        tableColumn.sortDescriptorPrototype = fileNameSortDescriptor
        // other codes
    }
}

А затем я добавил наследование от NSObject и вставил @objcMembers, чтобы предотвратить возникновение warning: Object <#object#> of class '<#class#>' does not implement methodSignatureForSelector: -- trouble ahead, а затем вызвал Signal SIGABRT при вызове selectedFiles.sort(using: tableView.sortDescriptors) (Ссылка: Объект X класса Y не реализует methodSignatureForSelector в Swift ).

@objcMembers class SelectedFiles: NSObject {
    let fileName: String
    let filePath: String
    override var description: String {
        return "\(fileName) at path \(filePath)"

    init(fileName: String, filePath: String) {
        self.fileName = fileName
        self.filePath = filePath
    }
}

Вот код для tableView(_:sortDescriptorsDidChange:) в NSTableViewDataSource:

extension ViewController: NSTableViewDataSource {
    func tableView(_ tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [NSSortDescriptor]) {
        var selectedFilesArray = NSArray(array: selectedFiles)
        selectedFilesArray = selectedFilesArray.sortedArray(using: tableView.sortDescriptors) as NSArray
        selectedFiles = selectedFilesArray as! [SelectedFiles]
        tableView.reloadData()
    }
}

Сейчас, все отлично работает.

...