Hello:
I've been studying up on How to populate an NSTableView with data from CoreData using a fetchRequest. A lot of the information I found is for Swift 3 and 4. I am using the latest Xcode Version with Swift 5.1. I've looked at the Apple Documentation, lots of tutorials, some responses in Apple CoreData Forum, and my implementation of tableViews with CoreData in my iOS app.
Using what I've found, I constructed the code below to be able to display data from my CoreData store in an NSTableView (MAC OSx app).
I set up the NSTableView inside of a ViewController, added the delegates, set the cell identifiers in interface builder, and setup for three columns.
I think that what I've done below is too much (It absolutely can't be "not enough"). In any case , no data is displayed in the table View.
I'd really appreciate some help with this.
Thanks in advance. Please let me know what I don't need.
import Cocoa
import CoreData
class RegistrationReportsViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
showRegisteredStudents()
tableView.dataSource = self as? NSTableViewDataSource
tableView.delegate = self as? NSTableViewDelegate
}
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
return frc
}()
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!
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.sortDescriptors = [NSSortDescriptor(key: "lastName", ascending: true)]
do {
let records = try managedContext.fetch(fetchRequest) as! [NSManagedObject]
print ("There are \(records.count) records")
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.persistentContainer.viewContext, sectionNameKeyPath: nil, cacheName: nil)
// Configure Fetched Results Controller
fetchedResultsController.delegate = self
print("First Name is \(records)")
self.tableView.reloadData()
return()
} catch {
fatalError("Failed to fetch employees: \(error)")
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController) {
tableView.beginUpdates()
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController) {
tableView.endUpdates()
}
}
}
var records: [NSManagedObject] = []
extension RegistrationReportsViewController : NSTableViewDataSource{
func numberOfRows(in tableView: NSTableView) -> Int{
return records.count
}
}
extension RegistrationReportsViewController : NSTableViewDelegate{
fileprivate enum CellIdentifiers {
static let lastNameCell = "LNCellID"
static let firstNameCell = "FNCellID"
static let middleNameCell = "MNCellID"
}
//NSTableViewDelegate
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let cell: NSTableCellView!
let column = tableView.tableColumns.firstIndex(of: tableColumn!)!
switch column {
case 0:
cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "lastName"), owner: nil) as? NSTableCellView
case 1:
cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "firstName"), owner: nil) as? NSTableCellView
case 2:
cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "middleName"), owner: nil) as? NSTableCellView
default:
return nil
}
configureCell(cell: cell, row: row, column: column)
return cell
}
fileprivate 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
}
}
}
extension RegistrationReportsViewController : NSFetchedResultsControllerDelegate{
func controller(_ controller: NSFetchedResultsController, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?){
switch type {
case .insert:
if let newIndexPath = newIndexPath {
tableView.insertRows(at: [newIndexPath.item], withAnimation: .effectFade)
}
case .delete:
if let indexPath = indexPath {
tableView.removeRows(at: [indexPath.item], withAnimation: .effectFade)
}
case .update:
if let indexPath = indexPath {
let row = indexPath.item
for column in 0.. if let cell = tableView.view(atColumn: column, row: row, makeIfNecessary: true) as? NSTableCellView {
configureCell(cell: cell, row: row, column: column)
}
}
}
case .move:
if let indexPath = indexPath, let newIndexPath = newIndexPath {
tableView.removeRows(at: [indexPath.item], withAnimation: .effectFade)
tableView.insertRows(at: [newIndexPath.item], withAnimation: .effectFade)
}
@unknown default:
fatalError()
}
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController) {
tableView.beginUpdates()
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController) {
tableView.endUpdates()
}
}