纯代码实现NSTableView调用makeView时始终无法创建NSTableCellView
问题描述
纯代码实现NSTableView时,调用tableView.makeView(withIdentifier:owner:)始终返回nil,导致无法显示单元格数据。表格能正常显示列标题、可导航30行,但数据无法渲染,已确认代理方法tableView(_:viewFor:row:)被正确调用,不想使用绑定方式解决。
代码示例
import Cocoa class ViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource { var students: [Student] = [] var tableView = NSTableView() var studentIdColumn = NSTableColumn(identifier: .init("student_id_column")) var nameColumn = NSTableColumn(identifier: .init("student_name_column")) var gpaColumn = NSTableColumn(identifier: .init("student_gpa_column")) override func viewDidLoad() { super.viewDidLoad() students = createStudents(numberOfStudents: 30) configureUI() } private func configureUI() { configureTable() view.addSubviews([ tableView ]) configureConstraints() } private func configureTableColumns() { studentIdColumn.width = 125 gpaColumn.width = 125 nameColumn.width = 550 studentIdColumn.title = "Student ID" nameColumn.title = "Student Name" gpaColumn.title = "GPA" tableView.addTableColumn(studentIdColumn) tableView.addTableColumn(nameColumn) tableView.addTableColumn(gpaColumn) } private func configureTable() { configureTableColumns() tableView.delegate = self tableView.dataSource = self } private func configureConstraints() { tableView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), tableView.topAnchor.constraint(equalTo: view.topAnchor), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) } private func createStudents(numberOfStudents: Int) -> [Student] { let firstNames = Constants.firstNames let lastNames = Constants.lastNames var students = [Student]() for _ in 0..<numberOfStudents { let studentId = generateStudentId() let firstName = firstNames[Int.random(in: 0..<firstNames.count)] let lastName = lastNames[Int.random(in: 0..<lastNames.count)] let gpa = generateGPA() let s = Student(studentId: studentId, name: "\(firstName) \(lastName)", gpa: gpa) students.append(s) } return students } private func generateStudentId() -> String { var studentId = "" var isDuplicate = false repeat { studentId = String(Int.random(in: 100000..<1000000)) isDuplicate = students.contains { student in student.studentId == studentId } } while isDuplicate return studentId } private func generateGPA() -> Double { return Double.random(in: 0..<5) } func numberOfRows(in tableView: NSTableView) -> Int { return students.count } func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { guard let cellView = tableView.makeView(withIdentifier: tableColumn!.identifier, owner: self) else { return nil } if tableColumn!.title == "Student ID" { cellView.textField?.stringValue = students[row].studentId } else if tableColumn!.title == "Student Name" { cellView.textField?.stringValue = students[row].name } else { cellView.textField?.stringValue = getGPAFormatter().string(from: NSNumber(value: students[row].gpa))! } return cellView } private func getGPAFormatter() -> NumberFormatter { let formatter = NumberFormatter() formatter.numberStyle = .decimal formatter.minimumFractionDigits = 2 formatter.maximumFractionDigits = 2 return formatter } }
解决方向
- 注册单元格视图类:NSTableView不会自动创建未注册的单元格类型,必须提前为每个列的identifier注册对应的视图类。修改
configureTable方法,添加注册逻辑:private func configureTable() { configureTableColumns() // 注册单元格视图 tableView.register(NSTableCellView.self, forIdentifier: studentIdColumn.identifier) tableView.register(NSTableCellView.self, forIdentifier: nameColumn.identifier) tableView.register(NSTableCellView.self, forIdentifier: gpaColumn.identifier) tableView.delegate = self tableView.dataSource = self } - 优化可选值处理:避免强制解包引发崩溃,修改代理方法中的可选绑定逻辑:
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { guard let tableColumn = tableColumn, let cellView = tableView.makeView(withIdentifier: tableColumn.identifier, owner: self) as? NSTableCellView else { return nil } switch tableColumn.identifier.rawValue { case "student_id_column": cellView.textField?.stringValue = students[row].studentId case "student_name_column": cellView.textField?.stringValue = students[row].name case "student_gpa_column": cellView.textField?.stringValue = getGPAFormatter().string(from: NSNumber(value: students[row].gpa)) ?? "0.00" default: break } return cellView } - 设置行高(可选):如果单元格内容显示不全,可自定义行高或开启自动行高:
// 在configureTable中添加 tableView.rowHeight = 28 // 固定行高 // 或开启自动行高 tableView.usesAutomaticRowHeight = true tableView.rowHeight = NSTableView.automaticDimension tableView.minimumRowHeight = 28
内容的提问来源于stack exchange,提问作者Macintoshuser_2
相关产品推荐
相关产品推荐

