Alex Alex - 10 months ago 71
Swift Question

NStableView does not show my data

I have a tableView with an image and a textField but they are not showing the data. What could be missing?

I have tableColumn identifier set as MainCell...
I converted obj-c from here to swift.

Any suggestions?

import Cocoa

class viewTime: NSViewController, NSTableViewDataSource, NSTableViewDelegate {

var tableContents:NSMutableArray = []

@IBOutlet var tableView: NSTableView!

override func viewDidLoad() {

let path: NSString = "/Library/Application Support/Apple/iChat Icons/Flags"
let fileManager:FileManager = FileManager.default
let directoryEnum:FileManager.DirectoryEnumerator = fileManager.enumerator(atPath: path as String)!

while let file = directoryEnum.nextObject() as? NSString{
let filePath:NSString = path.appendingFormat("/%@", file)
let obj:NSDictionary = ["image": NSImage(byReferencingFile:filePath as String), "name": file.deletingPathExtension]


func numberOfRows(in tableView: NSTableView) -> Int {
return tableContents.count

private func tableView(tableView: NSTableView, viewForTableColumn tableColumn: NSTableColumn?, row: Int) -> NSView! {
let cellView = tableView.make(withIdentifier: "MainCell", owner: self) as! NSTableCellView

let flag:NSDictionary = tableContents[row] as! NSDictionary
let identifier:NSString = tableColumn!.identifier as NSString

if (identifier == "MainCell") {

cellView.textField?.stringValue = flag["name"] as! String
cellView.imageView!.image = flag["image"] as? NSImage
return cellView
return nil


Answer Source

Translating Objective-C to Swift literally is always a bad idea.

  • First of all make sure that both datasource and delegate of the table view are connected to the view controller in Interface Builder.
  • Make sure also that the Identifier of the NSTableCellView is MainCell
  • Most important change: Create a custom struct, it makes things so much easier.

    struct Asset {
      var name : String
      var image : NSImage
  • Declare the data source array as Swift Array of the struct type.

     var tableContents = [Asset]()
  • This is viewDidLoad in real Swift code. Don't annotate types unless the compiler tells you to do (after let obj)

    override func viewDidLoad() {
      let url = URL(fileURLWithPath:"/Library/Application Support/Apple/iChat Icons/Flags")
      let enumerator = FileManager.default.enumerator(at: url, includingPropertiesForKeys: [], options: .skipsHiddenFiles, errorHandler: nil)!
      for case let fileURL as URL in enumerator {
        let asset = Asset(name: fileURL.deletingPathExtension().lastPathComponent, image: NSImage(contentsOf:fileURL)!)
  • numberOfRows is OK.

  • tableView:viewForColumn:Row can be simplified as there is only one identifier and one column.

    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
      let cellView = tableView.make(withIdentifier: "MainCell", owner: self) as! NSTableCellView
      let asset = tableContents[row]
      cellView.textField!.stringValue =
      cellView.imageView!.image = asset.image
      return cellView