Get data from table

I am new to Xcode macOS and Swift. I searched far and wide to find

a simple example for getting data values from a tableView.

I figured out a simple example and am posting it here in hopes that

it will help others.


The trick is getting the indexes from the table on screen and

then referencing your data source that is currently loaded in memory

using the indexes from the table.


The actual code is less than ten lines. Explaining it is an entire page.


This does use an extension which is a Swift file whose

wrapped extension name is the same as your primary ViewController.


The name of the extension files by convention is the name of

the ViewController you are extending with an added plus sign '+' and

finally the name of what this code page does or what this code page is.


In this case it would be something like

MainViewController+SimplePrintTableValuesExample

But it is not mandatory. You could call it 'beachBall. if you like.


What is mandatory is the extension inside the code.


My primary code page ViewController name is "MainViewController"

That is why this code is wrapped in the line beginning


extension MainViewController { // -- Mandatory if your main view controller name is 'MainViewController'


The rest of code is then wrapped in a single function - This is also mandatory

I am extending the function tableViewSelectionDidChange.

Xcode populated the rest of that line.


The output is in the console (debug area) at the bottom of your

Xcode screen.


The 'myDataArray' needs to be prepopulated first and

that array needs to already be in your tableView.


Then this code will run.


This is for macOS.


// -----------------------------------------------------------
// -- Getting data values from a tableView
// -----------------------------------------------------------
import Cocoa
import Foundation

extension MainViewController {
    // -----------------------------------------------------------
    // -- Note: that myDataArray is loaded and in memory.
    // -- That data is now showing inside of the tableView.
    // -- Now we want to do something with the rows the user
    // -- has selected.
    // -- also note: I'm only accessing a single column tableView.
    // -----------------------------------------------------------

    func tableViewSelectionDidChange(_ notification: Notification) {
        // -----------------------------------------------------------
        // -- This is an array to store the selected rows data.
        // -- In my case this is actually an instance array
        // -- in which I call .removeAll() on like this
        // -- myDataArray.removeAll()
        // -----------------------------------------------------------
        selectedRowsData[String] = []

        // -----------------------------------------------------------
        // -- Get the set of indexes for the rows that are selected.
        // -----------------------------------------------------------
        // -- myTableView.selectedRowIndexes
        // --    this is an index set containing
        // --    the indexes of the selected rows
        let selectedIndexSet = myTableView.selectedRowIndexes    
       
        // -----------------------------------------------------------
        // -- If your curious this is the quantity of rows selected.
        // -- I will be looping through this set in a moment.
        // -- SelectedIndexSet returns '# indexes' literally.
        // -- This index set contains something like ["2", "5", "9"]
        // -- uncomment the print line to see the number of
        // -- highlited rows
        // -- etc...
        // -----------------------------------------------------------
        // print("selectedIndexSet: There are \(selectedIndexSet)")
       
        // -----------------------------------------------------------
        // -- Now loop through the index set and extract
        // -- from the original data array "myDataArray",
        // -- the value that each row index points to.
        // -----------------------------------------------------------
        for index in selectedIndexSet {
            // -- This line is here in case no rows are highlited.
            // -- If no rows are highlited index will be -1
            // -- If index has a value less than zero this routine
            // -- will crash. 
            // -----------------------------------------------------------
            if index > -1 {
                // -----------------------------------------------------------
                // -- Append the actual data to selectedRowsData array
                // -- This will provide quoted string, comma separated values.
                // -- ["dataA", "dataB", "more data here"]
                // -----------------------------------------------------------
                selectedRowsData.append(myDataArray.self[index])
            }
        }
        print("selectedRowsData \n \(selectedRowsData)")
    }
}

Replies

Great you've learned something.


But what was the point ? I must be missing something.

You have TableView properties that can be used directly like

var indexPathsForSelectedRows: [IndexPath]?


Didn't it work ?

I am just starting in this language. Feel free to elaborate.

Assume a tablename of 'myTable' and a dataSource of 'myDataSourceArray'

Now, what is the command to access the cell data? I'm using Swift, Xcode 11.1

You should look at tutorial, but the principle is simple.


You declare how many sections and cells per section:

Here, if you have a single section with all the data of the dataSource:

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
  
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return myDataSourceArray.count
    }

You have a tableView func to populate the cells.

I assume that dataSource is an array of strings

If you have define the tableView cells with title and detail (a standard setup) and declared the identifier for cells as CellItem:


    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
     
        let cell = tableView.dequeueReusableCell(withIdentifier: "CellItem", for: indexPath)
     
        // Configure the cell...
        cell.textLabel!.text = "Cell \(indexPath.row+1)"     // Just show the cell number
        cell.detailTextLabel?.text = myDataSourceArray[indexPath.row]     // The text in the array

        return cell
    }


When you want to modify the table, you usually modify the dataSource (array) and ask for tableView.reload()

A bit esoteric but let me suggest that you look at the question a bit differently:


>getting data values from a tableView


Under "Model-View-Controller" logic this is ***-backwards. Your Model knows the data values. Your Controller then displays those values in your View - your TableView. There should never be a need to 'get values from a tableView'. Just like there is no need for your mouth to 'know' what you are speaking. You do need to know how to display data values from your Model in a tableView and you do that through the Controller's cellForRowAtIndexPath.

I think I see our differences. I'm using NSView. NSView is used for Mac. UIView is used for IOS. I'm not coding IOS.

In any event, what I have works well. Thanks for the responses.


https://stackoverflow.com/questions/5283218/what-is-the-difference-between-uiview-and-nsview

Sure, but the principle is exactly the same.


Just API are slightly different (notably because NSTables may have multiple columns


    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
                if let cellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "CellItem"), owner: self) {
                    (cellView as! NSTableCellView).textField?.stringValue = myDataSourceArray[row]
                    return cellView
                } else {
                    return nil
                }
}

ANyway, you could now close the thread.