Search code examples
macoscocoacelleditnstableview

Edit data in the model according to the user's input in view-based NSTableView


I have a view-based NSTableView where all the cells are editable. I need to refresh the data from the model every time the user modifies a textField from the view.

All the doc I find is related to the cell-based NSTableView.

Does anyone have a clue about this?

EDIT:

I'm using data source to populate this NSTableView.

This is the code of the Controller of the NSTableView

class ViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource {

@IBOutlet var globalView: NSView!
@IBOutlet var songsTableView: NSTableView!

var tableContents = NSMutableArray()


override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.

    for (song) in songManager.songs {
        var obj = Dictionary<String,String>()
        obj["title"] = song.title
        obj["artist"] = song.artist
        tableContents.addObject(obj)
    }
    songsTableView.reloadData()
}


func numberOfRowsInTableView(tableView: NSTableView) -> Int {
    return tableContents.count
}



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

    var obj = tableContents[row] as Dictionary<String,String>
    let column = tableColumn?.identifier
    var cellView = tableView.makeViewWithIdentifier(column!, owner: self) as NSTableCellView

    if column == "title" {
        cellView.textField?.stringValue = obj["title"]!
    }
    if column == "artist" {
        cellView.textField?.stringValue = obj["artist"]!
    }

    cellView.textField?.editable = true

    return cellView
}    
}

And this is the code of the class that manages the data.

var songManager = SongManager()


struct song {
    var title = "No name"
    var artist = "No artist"
}

class SongManager: NSObject {

    var songs = [song]()

    func addSong(title: String, artist: String) {
        songs.append(song(title: title, artist: artist))
    }

}

I have not touched the row that the storyboard creates by default, so I guess it contains a single NSTextField.

I get to display the data, but cannot detect when the user tried to modify a textfield.


Solution

  • Given how things are currently set up, the simplest approach is probably to connect the text field's action selector to an action method on a target, such as your controller. You can do that in IB or in your tableView(_:viewForTableColumn:row:) method.

    In that action method, you can call songsTableView.rowForView(sender) to determine which row was edited. Each column's text field would have a different action method, such as changeTitle() or changeArtist(), so that you know which column was edited. (You could also use songsTableView.columnForView(sender), then get the table column by using the index in songsTableView.tableColumns[col], and checking the returned column's identifier. For that, you would assign specific identifiers to the columns rather than letting IB assign them automatically.)

    Once you have the row, you look up your dictionary using var obj = tableContents[row] as Dictionary<String,String> and set the value for the key appropriate to the action method (or column identifier) to the sender's stringValue.