自定义NSTableHeaderCell在表格调整大小时崩溃问题求助
解决NSTableView自定义表头单元格调整大小崩溃的问题
问题根源
NSTableView在调整列宽、表格大小等场景下,会复制(copy)现有的表头单元格实例来更新UI。如果自定义的NSTableHeaderCell子类没有实现NSCopying协议,复制后的新实例不会包含你的自定义属性(比如myFont),导致绘制时访问nil属性引发崩溃;同时系统原生font属性会被父类的拷贝逻辑处理,但系统可能在后续重置该属性为默认值,这也是直接用font会恢复默认的原因。
解决方案
1. 实现NSCopying协议,确保自定义属性被正确拷贝
重写copy(with:)方法,手动拷贝自定义属性及父类的关键样式属性,保证复制后的单元格和原实例状态一致:
class MyTableHeaderCell: NSTableHeaderCell, NSCopying { var myFont: NSFont? func copy(with zone: NSZone? = nil) -> Any { // 创建新的单元格实例 let copiedCell = MyTableHeaderCell(textCell: self.stringValue) // 拷贝自定义属性 copiedCell.myFont = self.myFont // 拷贝父类的核心样式属性(按需补充) copiedCell.alignment = self.alignment copiedCell.textColor = self.textColor copiedCell.backgroundColor = self.backgroundColor copiedCell.highlighted = self.highlighted return copiedCell } }
2. 重写绘制方法,确保使用自定义字体且处理nil情况
避免强制解包myFont,绘制时优先使用自定义字体,回退到系统默认字体防止崩溃:
override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) { let targetFont = myFont ?? super.font NSGraphicsContext.saveGraphicsState() // 设置字体后绘制文本 targetFont?.set() self.stringValue.draw(in: cellFrame, withAttributes: [.font: targetFont!]) NSGraphicsContext.restoreGraphicsState() }
3. 可选:通过代理方法兜底确保样式不被重置
如果仍出现样式丢失,可以在表格视图的代理方法中强制重置自定义属性,确保表头绘制时状态正确:
func tableView(_ tableView: NSTableView, willDisplayHeaderCell cell: NSTableHeaderCell, forTableColumn tableColumn: NSTableColumn) { guard let customCell = cell as? MyTableHeaderCell else { return } // 重新设置自定义字体(避免被系统逻辑覆盖) customCell.myFont = NSFont.systemFont(ofSize: 14) }
关于自定义NSColor崩溃的补充
如果存储自定义NSColor也崩溃,同样要在copy(with:)方法中拷贝该属性,且绘制时处理nil情况,逻辑和myFont完全一致。
内容的提问来源于stack exchange,提问作者dcsalmon
相关产品推荐
相关产品推荐

