0
votes

I have an NSView with a NSTableView called personTableView. In the ViewController class, I have the following code:

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
    personTableView.delegate = self
    personTableView.dataSource = self
    personTableView.reloadData()

}

and have extended the class to with NSTableViewDelegate and NSTableViewDataSource

However, when the view appears, the table shows the following (there are only 2 entries that the table should display):

enter image description here

On my window, I have a button which invokes the following action:

@IBAction func refreshButton(_ sender: NSButton) {
    let result = CoreDataHandler.fetchCount()
    print("Row Count:\(result)")
    personTableView.reloadData()
    codeTableView.reloadData()
}

which when pressed, populates my TableView. I don't understand why it won't load automatically?

I have also tried putting the personTableView.reloadData() into viewWillAppear and viewDidAppear to no avail.

Update:

This is the fetchCount():

static func fetchCount() -> Int {
    let context = getContext()
    do {
        let count = try context.count(for: Person.fetchRequest())
        NSLog("Count from fetchCount: %d", count)
        return count
    } catch {
        return 0
    }
}

For information, this is the Table Delegate and DataSource functions:

extension ViewController: NSTableViewDataSource {
    func numberOfRows(in tableView: NSTableView) -> Int {
        if tableView == self.personTableView {
            let result = CoreDataHandler.fetchCount()
            //NSLog("Rows in Ext: %@",result)
            return result
        }
        if tableView == self.codeTableView {
            let row = personTableView.selectedRow
            if row > -1 {
                let person = CoreDataHandler.fetchPerson()?[row]
                print("Person= \(String(describing: person?.first))")
                //let result = CoreDataHandler.fetchCodes(person: person!)
                let result = person?.codes
                //print("Person from result: \(String(describing: result?.first.whosAccount?.ibAccount))")
                let count = result!.count
                print("Rows in Codes from viewController dataSource: \(count)")
                return count
            } else {
            return 0
            }
        }
        return 0
    }
}

extension ViewController: NSTableViewDelegate {

    func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {

        if tableView == self.personTableView {
            guard let person = CoreDataHandler.fetchPerson()?[row] else {
                return nil
            }

            if let cell = tableView.makeView(withIdentifier: (tableColumn!.identifier), owner: nil) as? NSTableCellView {
                if tableColumn == tableView.tableColumns[0]  {
                    cell.textField?.stringValue = (person.first ?? nil) ?? ""
                } else if tableColumn == tableView.tableColumns[1] {
                    cell.textField?.stringValue = (person.last ?? nil) ?? ""
                } else {
                    cell.textField?.stringValue = (person.ibAccount ?? nil) ?? ""
                }

                return cell

            } else {
                return nil
            }
        }

        if tableView == self.codeTableView {

            let personRow = personTableView.selectedRow
            if personRow > -1 {
                let person = CoreDataHandler.fetchPerson()?[personRow]
                guard let code = CoreDataHandler.fetchCodes(person: person!)?[row] else {
                    return nil
                }

                if let cell = tableView.makeView(withIdentifier: (tableColumn!.identifier), owner: nil) as? NSTableCellView {
                    if tableColumn == tableView.tableColumns[0]  {
                        cell.textField?.stringValue = (String(code.number) )
                        //cell.textField?.stringValue = person?.codes?.allObjects[row] as! String
                    } else if tableColumn == tableView.tableColumns[1] {
                        cell.textField?.stringValue = code.code!

                    } else if tableColumn == tableView.tableColumns[2] {
                        cell.textField?.stringValue = (code.whosAccount?.ibAccount ?? "")
                    }

                    return cell

                } else {
                    return nil
                }
            }
        }

        return nil

    }



}
2
Can you share what CoreDataHandler.fetchCount() does?DionizB
Don't fetch anything in numberOfRows and in objectValueFor. Don't do that. It's unnecessarily expensive and inefficient. Fetch the stuff once and reload the table view or use NSFetchResultsController and Cocoa Bindings. The latter reduces your code by 2/3.vadian
@vadian: Thanks for the suggestion. I am fairly new to this. If I fetch that data once and have nothing in numberof Rows and objectValueFor, how do the tables get updated?pdoak
Fetch the data into a data source array var people = [Person](). Return people.count in numberOfRows and people[row] in objectValueFor. And replace (person.first ?? nil) ?? "" with person.first ?? "". The second nil-coalescing operator is redundant.vadian
@vadian: Okay but how do I return the array[row] in objectValueFor as I thought I had to return each column separatelypdoak

2 Answers

0
votes

You've mixed up tableView(_:objectValueFor:row:) of NSTableViewDataSource and tableView(_:viewFor:row:) of NSTableViewDelegate. Replace

func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any?

by

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView?

or return strings from tableView(_:objectValueFor:row:)

0
votes

It seems like the table view is being populated based on data stored in the result variable. Try making the call to let result = CoreDataHandler.fetchCount() in viewDidLoad