Kodeco Forums

macOS NSTableView Tutorial

Table views are one of the most important macOS UI controls. Get up to speed with how to use them with this macOS NSTableView tutorial.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/830-macos-nstableview-tutorial

Thank you. I enjoyed that.

Hi,
I am interested in the original (Objective C) tutorial.
However, I cannot get to it. The ā€œoriginalā€ link points back to your new (Swift)
tutorial. I tried to get the original tutorial from the ā€œTutorial Archivesā€,
but it has the same problem. It points to your tutorial. (it is like Catch XXII symptom)
Could you please let me know how to get to the original tutorial?
Thank you
Hynek

Hi Hynek

The original was never written in Objective-C. The update took the tutorial from Swift 2 to Swift 3

You are right in that the original link takes you back to this version however. Ill track it down and get it properly linked soon.

Hi,
thanks for your reply. One suggestion for updates - it might be good to contain info ā€œfromā€ (what was the original) and ā€œtoā€ (what is now new tutorial). In such case, if the link to original does not work, the info will be sufficient to get the information about the original.
Thanks
Hynek

Thank you for the fantastic tutorial. Iā€™m new to all this, so it is nice to get such good explanations (and also using Swift since so much of Appleā€™s documents are still in Obj-C).

I do have one question that I havenā€™t been able to figure out. Is there a way to make one of the columns in a TableView an input column? Iā€™m thinking of an App that works a bit like an Excel Spreadsheet. I want one column that has the data entry and then two more columns that do the calculations based on the current data and row above it. I havenā€™t found how to create a column of input data though.

Thanks ~ M

Being able to edit stuff in a tableview is fairly easy. You just implement the NSTableViewDatasource method

optional func tableView(_ tableView: NSTableView, setObjectValue object: Any?, for tableColumn: NSTableColumn?, row: Int)

The NSTableviewDelegate method

func tableView(NSTableView, shouldEdit: NSTableColumn?, row: Int)

may come in handy too.

You edit your object and invoke whatever side-effects in your data that you want to, then reloadData() on the tableview.

You may also need to set the relevant column to Editable in Interface Builder.

Iā€™ve been trying this, Warren, making a field editable, and itā€™s not working I think because the tableview is set to View based. Changing it to Cell Based kicks out all the Table Cell Views and breaks everything. I donā€™t suppose there are any other thoughts on how to catch changes to editable cells?

Thanks.

Yes, Sorry my fault for not paying enough attention. That only works for cell based tables.

This SO answer here holds all the magic. cocoa - View based NSTableView editing - Stack Overflow

Essentially - kick the cells textfield into Editable mode in IB and then send its action to the view controller to update your datasource. You can get the row/column information by asking the tableviewā€¦

@IBAction func endEditing(_ sender: Any) {
        
        if let textField = sender as? NSTextField {
            let row = tableView.row(for: textField )
            let column = tableView.column(for: textField)
            print ("edit row \(row) - column \(column) -> \(textField.stringValue)")
        }
    }

That did it. Thanks. So simple too.

One last question; Iā€™d quite like to put, say, a MASSHortcutView (derived from a Custom View) and maybe a button into cells. Iā€™ve tried but nothing shows. Can it be done?

thanks.

I didnt have any issues dragging an NSView into NSTableCellView and constraining it there but maybe you need to leverage the func register(NSNib?, forIdentifier: String) API here.

Construct your view hierarchy in a XIB which has a NSTableCellView as its top level object and then register that NIB before you use it.

Now it works. I must have been doing something wrong before. I didnā€™t need the nib. Just set the Custom View class to MASShortcutView and it was fine. It might be different for the button, though but I can figure that out now.
thanks again.

Selecting a directory when running this code without any changes gives me the following messages among others prior to it. Iā€™m running Sierra 10.12.3 and Xcode Version 8.2.1 (8C1002) using Swift 3.

2017-03-11 10:52:11.044337 FileViewer[16156:845670] [Layout] Detected missing constraints for <NSVibrantSplitDividerView: 0x600000185620>. It cannot be placed because there are not enough constraints to fully define the size and origin. Add the missing constraints, or set translatesAutoresizingMaskIntoConstraints=YES and constraints will be generated for you. If this view is laid out manually on macOS 10.12 and later, you may choose to not call [super layout] from your override. Set a breakpoint on DETECTED_MISSING_CONSTRAINTS to debug. This error will only be logged once.
ā€¦
error: Error Domain=BRCloudDocsErrorDomain Code=12 ā€œApp library not found: ā€˜com.apple.Documentsā€™ā€ UserInfo={NSDescription=App library not found: ā€˜com.apple.Documentsā€™}
Represented object: file:///Users/michaeltoth/Documents/quiet-sky-7167/spec/

Is this a version issue?

Went through the entire tutorial without a single problem! Very clear. Up to date. Thank you some much!

MacBookPro
Sierra 10.12.5
Xcode 8.3.3

P.S. I even bought a copy of DevSketch to say thank you in a more meaningful way!
Mike

Thanks so much for the feedback :]

Hi, first, thanks for all the great tutorials! I was wondering if you can point out how changing the font color of a selected TableRowView can be achieved manually.

For example when I define a different font color for the first row and a different one for all the following ones in
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { it will overwrite the font color but still thereā€™s no way to change it for selected ones. Also it overwrites the common color change for selected rows. Any idea?

As you can see from the name, Iā€™v mainly been in iOS, but Iā€™m working on a complimentary app in macOS.
Always fun to learn something new.

However, Iā€™ve run into a bit of bother.
I have, in the iOS app a table cell that I need to duplicate in the macOS app.

14

It looks like this, where I have several labels, image and some coloured dots.
Is this possible to create in macOS? Is there a tutorial somewhere that show how something like this can be achieved?

Thanks for any suggestions and/or help.

Modern macOS table cells are NSViews that you recycle so you can do anything you care to construct in IB or programmatically

The important API youā€™ll want to use on NSTableView here are
func register(NSNib?, forIdentifier: String) to set your cell up via IB
func make(withIdentifier identifier: String, owner: Any?) -> NSView? to get new or recycled instance (like dequeue)

And on the delegateā€¦
func tableView(NSTableView, viewFor: NSTableColumn?, row: Int)

NSTableView has much the same API as UITableView so all the stuff like setting heights is the same. I dont think its gotten automatic cell heights yet.

Best docs here are the apple docs Apple Developer Documentation which explain a lot about views and using them in tables

Thanks
Warren

This one was interesting. Essentially you need to subclass NSTableRowView and supply it via the delgate method.

func tableView(NSTableView, rowViewForRow: Int)

That class displays the highlight and you can adjust it to your hearts content.

https://developer.apple.com/documentation/appkit/nstablerowview

How do I add a search bar to the top of my NSTableView?