3

I have a feeling this table cell display problem has a simple answer but, I clearly need greater wisdom than mine to find it.

Here's my textbook controller, delegate and datasource class for the table and the enclosing view ...

import Cocoa

class Table8020ViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource {

    var tokenText: [String] = ["alpha", "beta", "gamma", "delta", "epsilon", "zeta"]

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    func numberOfRowsInTableView(aTableView: NSTableView) -> Int {
        println("numberOfRowsInTableView = \(tokenText.count)")
        return tokenText.count
    }

    func tableView(aTableView: NSTableView, objectValueForTableColumn aTableColumn: NSTableColumn?, row rowIndex: Int) -> AnyObject? {

        var result = aTableView.makeViewWithIdentifier(aTableColumn!.identifier, owner: self) as! NSTableCellView
            println("textField in  = \(result.textField!.stringValue)")

            result.textField!.stringValue = tokenText[rowIndex]

            println("textField out = \(result.textField!.stringValue)")
            return result
    }
}

I log the updates to the .textField which seems to work ok.

numberOfRowsInTableView = 6
textField in  = Table View Cell
textField out = alpha
textField in  = Table View Cell
textField out = beta
textField in  = Table View Cell
textField out = gamma
textField in  = Table View Cell
textField out = delta
textField in  = Table View Cell
textField out = epsilon
textField in  = Table View Cell
textField out = zeta

But the actual table display retains the original interface builder values! 'Table View Cell' Something mysterious appears to be happening after after the 'return result'.

I'm using the latest Xcode Version 6.3 (6D570) with Swift V1.2

Rojer
  • 33
  • 4

1 Answers1

8

You're making a couple of mistakes.

Firstly you're returning the wrong kind of value from tableView:objectValueForTableColumn:row. This method isn't requesting a view instance, it's requesting the object that your view instance will be representing. In other words it wants to know what model object the view will be displaying. In each case your model object is very simple - it's one of the strings in the tokenText array.

func tableView(tableView: NSTableView,
    objectValueForTableColumn tableColumn: NSTableColumn?,
    row: Int) -> AnyObject? {
        return tokenText[row]
}

Secondly you've failed to implement tableView:viewForTableColumn:row:. This is where you create a view for each cell in your table and tell that view which bits of the model object you want to display. In each case your model object is just a string, so you essentially tell the view to display the entire model object in its textField:

func tableView(tableView: NSTableView,
    viewForTableColumn tableColumn: NSTableColumn?,
    row: Int) -> NSView? {

        var view = tableView.makeViewWithIdentifier(tableColumn!.identifier,
            owner: self) as! NSTableCellView
        view.textField!.stringValue = tokenText[row]

    return view
}
Paul Patterson
  • 6,840
  • 3
  • 42
  • 56
  • Thanks for the prompt and clear reply. Problem resolved. Now reflecting on my confusion ... WHY is the 'objectValue' of mandatory importance? I assume this could be any object, as simple as my 'String' example here, or quite complex like say an 'InvestmentPortfolio'. Apart from keeping a pointer to the object, the table cannot really do anything else with such a thing, or can it? – Rojer Apr 14 '15 at 12:47
  • 3
    In this simple example you don't need to implement ``tableView:objectValueForTableColumn:row:`` - you can delete it and your app will build and run without any problems. In more complex examples however the ``objectValue`` property of the ``NSTableCellView`` is more important. I'm thinking in particular of when you populate a table-view using *bindings*. If you give this a go you'll see that everything can be done via *Interface Builder*, and the way you tell the controls on the ``NSTableCellView`` what part of the model they should display is via this view's ``objectValue``. – Paul Patterson Apr 14 '15 at 21:57
  • Excellent. That all makes perfect sense. Your contribution to my growing wisdom is much appreciated. – Rojer Apr 15 '15 at 10:21
  • I really hope SO allow me for upvoting for this twice! :) – Itachi Mar 03 '17 at 06:58