Cocoa绑定:NSOutlineView指定列排序异常求助
首先咱们来拆解下你遇到的崩溃原因:当你把列绑定到binaryData这个关联属性时,NSTreeController尝试用MyBinary对象来做排序比较,但你的MyBinary类是NSManagedObject的子类,默认并没有实现compare:方法,所以触发了unrecognized selector错误。
要实现你想要的「按按钮启用/禁用分组排序」的需求,我给你两个可行的方案:
方案一:使用计算属性替换直接绑定关联对象
这是最简单的实现方式,我们在包含binaryData关联的模型类(假设叫MyItem)里添加一个布尔类型的计算属性,用来标识是否存在关联的MyBinary对象:
import CoreData extension MyItem { @objc var hasBinaryData: Bool { // 直接判断关联对象是否存在 return binaryData != nil } }
然后回到IB中,把该列的Model Key Path从binaryData改成hasBinaryData,其他绑定设置保持不变。
这样点击列头排序时,系统会自动按布尔值完成分组排序:
- 升序:禁用按钮的项(
false)在前,启用的(true)在后 - 降序:启用按钮的项在前,禁用的在后
完美匹配你的需求,而且不会再出现崩溃。
方案二:自定义排序描述符(更灵活的控制)
如果你需要更定制化的排序逻辑(比如调整分组的前后顺序,或者分组内再叠加其他排序规则),可以通过NSTreeControllerDelegate来为指定列设置自定义排序描述符:
- 先让你的ViewController遵循
NSTreeControllerDelegate协议:
class YourViewController: NSViewController, NSTreeControllerDelegate { // ... 其他现有代码 }
在IB中把NSTreeController的
delegate拖线关联到你的ViewController。实现代理方法,针对目标列返回自定义排序描述符:
func treeController(_ treeController: NSTreeController, sortDescriptorsForSortKey sortKey: String, ascending: Bool) -> [NSSortDescriptor]? { // 匹配我们定义的计算属性key guard sortKey == "hasBinaryData" else { // 其他列保持默认排序逻辑 return nil } // 自定义比较逻辑:比如强制升序时让启用按钮的项排在最前面 let customComparator: Comparator = { obj1, obj2 in let bool1 = obj1 as! Bool let bool2 = obj2 as! Bool if bool1 == bool2 { return .orderedSame } // 升序:true在前;降序:false在前 return ascending ? (bool1 ? .orderedAscending : .orderedDescending) : (bool1 ? .orderedDescending : .orderedAscending) } let sortDescriptor = NSSortDescriptor(key: sortKey, ascending: ascending, comparator: customComparator) return [sortDescriptor] }
这个方案可以让你完全掌控排序逻辑,满足更多个性化的排序需求。
补充:为什么原来的绑定会崩溃?
再明确下问题根源:binaryData是关联的MyBinary实例,当NSTreeController尝试排序时,会调用对象的compare:方法,但MyBinary作为NSManagedObject子类,默认没有实现这个方法,所以系统找不到对应的选择器,导致崩溃。换成布尔值计算属性后,系统可以使用布尔值的默认比较逻辑,或者我们自定义的比较器,就不会出现问题了。
内容的提问来源于stack exchange,提问作者vomi

