Hello:
I am getting the following error:
Illegal NSTableView data source: Must implement numberOfRowsInTableView: and tableView:objectValueForTableColumn:row:
My tableView implementation is as follows:
import Cocoa
import CoreData
class RegistrationReportsViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
showRegisteredStudents()
tableView.dataSource = self
tableView.delegate = self
tableView.reloadData()
}
private lazy var fetchedResultsController: NSFetchedResultsController = {
let fetchRequest: NSFetchRequest = Registration.fetchRequest()
let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.persistentContainer.viewContext, sectionNameKeyPath: nil, cacheName: nil)
frc.delegate = (self as! NSFetchedResultsControllerDelegate)
return frc
}()
var items: [NSManagedObject] = []
var managedObjectContext = (NSApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "ScorcentMasterReview")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error {
fatalError("Unresolved error \(error)")
} })
return container
}()
@IBOutlet weak var tableView: NSTableView!
var firstNameItem = "LAST"
var middleNameItem = "MIDDLE"
var lastNameItem = "FIRST"
func showRegisteredStudents() {
guard (NSApplication.shared.delegate as? AppDelegate) != nil else {
return
}
let managedContext = (NSApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let fetchRequest = NSFetchRequest(entityName: "Registration")
fetchRequest.returnsObjectsAsFaults = false
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "lastName", ascending: true)]
do {
let items = try managedContext.fetch(fetchRequest) as! [NSManagedObject]
print ("There are \(items.count) items")
_ = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.persistentContainer.viewContext, sectionNameKeyPath: nil, cacheName: nil)
// Configure Fetched Results Controller
print("Records are \(items)")
self.tableView.reloadData()
return()
} catch {
fatalError("Failed to fetch employees: \(error)")
}
}
}
extension RegistrationReportsViewController: NSTableViewDataSource{
func numberOfRowsInTableView(tableView: NSTableView) -> Int {
let numberOfRows:Int = items.count
return numberOfRows
}
}
//NSTableViewDelegate
extension RegistrationReportsViewController: NSTableViewDelegate{
func configureCell(cell: NSTableCellView, row: Int, column: Int){
let registration = fetchedResultsController.fetchedObjects! [row]
switch column {
case 0:
cell.textField?.stringValue = registration.lastName ?? ""
case 1:
cell.textField?.stringValue = registration.firstName ?? ""
case 2:
cell.textField?.stringValue = registration.middleName ?? ""
default:
break
}
func tableView(tableView: NSTableView!, objectValueForTableColumn tableColumn: NSTableColumn!, row: Int) -> AnyObject!{
_ = fetchedResultsController.fetchedObjects! [row]
let cell = tableView.makeView(withIdentifier: (tableColumn!.identifier), owner: self) as? NSTableCellView
let column = tableView.tableColumns.firstIndex(of: tableColumn!)!
// cell?.textField?.stringValue = registration[(tableColumn?.identifier.rawValue)!]!
configureCell(cell: cell!, row: row, column: column)
return cell
}
}
I would appreciate any help that points me in the right direction. Thanks.
It is normal delegate is not called when 0 row. But as soon as at least 1, should be called.
Your code is wrong:
extension RegistrationReportsViewController: NSTableViewDelegate{
func configureCell(cell: NSTableCellView, row: Int, column: Int){
let registration = fetchedResultsController.fetchedObjects! [row]
print ("Start NSTableView Delegate")
switch column {
case 0:
cell.textField?.stringValue = registration.lastName ?? ""
case 1:
cell.textField?.stringValue = registration.firstName ?? ""
case 2:
cell.textField?.stringValue = registration.middleName ?? ""
default:
break
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView?{
let cell = tableView.makeView(withIdentifier: (tableColumn!.identifier), owner: self) as? NSTableCellView
let column = tableView.tableColumns.firstIndex(of: tableColumn!)!
configureCell(cell: cell!, row: row, column: column)
return cell
}
}
}
Look, viewFor is defined inside configureCell.
So it is not visible as a delegate func.
Correct code is:
extension RegistrationReportsViewController: NSTableViewDelegate {
func configureCell(cell: NSTableCellView, row: Int, column: Int) {
let registration = fetchedResultsController.fetchedObjects! [row]
print ("Start NSTableView Delegate")
switch column {
case 0:
cell.textField?.stringValue = registration.lastName ?? ""
case 1:
cell.textField?.stringValue = registration.firstName ?? ""
case 2:
cell.textField?.stringValue = registration.middleName ?? ""
default:
break
}
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView?{
let cell = tableView.makeView(withIdentifier: (tableColumn!.identifier), owner: self) as? NSTableCellView
let column = tableView.tableColumns.firstIndex(of: tableColumn!)!
configureCell(cell: cell!, row: row, column: column)
return cell
}
}
Note: a clear writing, with correct identation, does help to see it immediately.