NSTableView - 使用 NSSortDescriptor 排序 collection 的更好解决方案
NSTableView - Better solution for sorting collection with NSSortDescriptor
我有一个 NSTableView,其中有 2 列绑定了自定义类型 (SelectedFiles
) 数组,如 File Name
和 File Path
,单击 header 后,我想要它为了按升序/降序对数据进行排序,我用 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()
}
}
我对 table 视图中数据的自定义 collection:
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()
}
}
在我改用这个解决方案后,它在升序/降序之间快速切换时效果很好。但是,当涉及到删除 collection 中的 objects 时,当我尝试从 collection 和 [=] 中删除多个 objects 时,它会抛出 Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
45=] 查看一些特定文件。
所以,我在考虑是否应该通过使用 NSSortDescriptor
(通过更正我的第一种方法使用 old-fashioned 方法)来改变实现此 header 排序的方法为了摆脱这个问题,我不得不承认我的第二种方式有点尴尬(更像是一个计划C)。
我已经浏览了关于这个主题的多篇 Whosebug 帖子,我尝试了他们所有的方法,尤其是 this one,我没有使用 CoreData,它的解决方案不适合我的情况。
请问有谁能帮忙指路吗?
我从 Apple Developer Site 和其他一些 Whosebug 帖子中找到了 NSTableView 指南,我发现自己是 Swift 4:
的可行解决方案
我在 ViewController
class 下的 viewDidLoad()
中将 sortDescriptorPrototype
设置为 fileNameSortDescriptor
。
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
发生然后在调用selectedFiles.sort(using: tableView.sortDescriptors)
时导致Signal SIGABRT
(参考: Object X of class Y does not implement methodSignatureForSelector in 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
}
}
这是 NSTableViewDataSource
中 tableView(_:sortDescriptorsDidChange:)
的代码:
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()
}
}
现在,一切正常。
我有一个 NSTableView,其中有 2 列绑定了自定义类型 (SelectedFiles
) 数组,如 File Name
和 File Path
,单击 header 后,我想要它为了按升序/降序对数据进行排序,我用 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()
}
}
我对 table 视图中数据的自定义 collection:
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()
}
}
在我改用这个解决方案后,它在升序/降序之间快速切换时效果很好。但是,当涉及到删除 collection 中的 objects 时,当我尝试从 collection 和 [=] 中删除多个 objects 时,它会抛出 Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
45=] 查看一些特定文件。
所以,我在考虑是否应该通过使用 NSSortDescriptor
(通过更正我的第一种方法使用 old-fashioned 方法)来改变实现此 header 排序的方法为了摆脱这个问题,我不得不承认我的第二种方式有点尴尬(更像是一个计划C)。
我已经浏览了关于这个主题的多篇 Whosebug 帖子,我尝试了他们所有的方法,尤其是 this one,我没有使用 CoreData,它的解决方案不适合我的情况。
请问有谁能帮忙指路吗?
我从 Apple Developer Site 和其他一些 Whosebug 帖子中找到了 NSTableView 指南,我发现自己是 Swift 4:
的可行解决方案我在 ViewController
class 下的 viewDidLoad()
中将 sortDescriptorPrototype
设置为 fileNameSortDescriptor
。
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
发生然后在调用selectedFiles.sort(using: tableView.sortDescriptors)
时导致Signal SIGABRT
(参考: Object X of class Y does not implement methodSignatureForSelector in 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
}
}
这是 NSTableViewDataSource
中 tableView(_:sortDescriptorsDidChange:)
的代码:
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()
}
}
现在,一切正常。