Swift中基于视图的NSTableView不显示内容

时间:2015-08-31 15:55:23

标签: swift nstableview

我试图在基于视图的NSTableView中显示非常基本的数据结构。经过几个小时的搜索,我终于达到了大部分桌面设置的地步。行数是正确的,我知道所有单元格都执行func tableView(tableView: NSTableView, objectValueForTableColumn tableColumn: NSTableColumn?, row: Int)方法,因为它在控制台中输出了正确的数据。不幸的是,该表显示的是默认值,而不是我的数据数组中的String

The table view doesn't display the correct data

以下是代码:

ViewController.swift

import Cocoa

class ViewController: NSViewController {

    @IBOutlet weak var myTableView: NSTableView!
    var files = [FilesListData]()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.setupSampleFiles()
    }
    override func viewDidAppear() {
        super.viewDidAppear()
    }

    func setupSampleFiles() {
        let file1 = FilesListData(file: "test.mp3", title: "test")
        let file2 = FilesListData(file: "test2.mp3", title: "test 2")

        self.files = [file1, file2]
    }
}

extension ViewController: NSTableViewDataSource {  
    func numberOfRowsInTableView(tableView: NSTableView) -> Int {
        return self.files.count
    }

    func tableView(tableView: NSTableView, objectValueForTableColumn tableColumn: NSTableColumn?, row: Int) -> AnyObject? {
        let cellView: NSTableCellView = tableView.makeViewWithIdentifier((tableColumn!.identifier), owner: self) as! NSTableCellView

        let fileData = self.files[row]
        if tableColumn!.identifier == "fileCol" {
            cellView.textField!.stringValue = fileData.file
        } else if tableColumn!.identifier == "titleCol" {
            cellView.textField!.stringValue = fileData.title
        } else {
            cellView.textField!.stringValue = "N/A"
        }
        return cellView
    }
}

extension ViewController: NSTableViewDelegate {
}

FilesListData.swift

import Foundation

class FilesListData: NSObject {
    var file: String
    var title: String

    override init() {
        self.file = String()
        self.title = String()
    }

    init(file: String, title: String) {
        self.file = file
        self.title = title
    }
}

还有一些注意事项:在故事板中,我确实为视图控制器创建了dataSourcedelegate的插座。我的前2列的标识符设置为" fileCol"和" titleCol"。项目编译并运行时没有任何错误或警告。以下是我的故事板的一些截图。

Objects tree

Identifier for the first column

1 个答案:

答案 0 :(得分:1)

看起来你混淆了两种不同的方法。 数据源方法tableView(_:objectValueForTableColumn:row:)用于返回数据对象,而不是单元格视图。 委托方法tableView(_:viewForTableColumn:row:)用于返回单元格视图,可能配置了适合列和行的数据。

所以,你可以将前者重写为:

func tableView(tableView: NSTableView, objectValueForTableColumn tableColumn: NSTableColumn?, row: Int) -> AnyObject? {
    let fileData = self.files[row]
    if tableColumn!.identifier == "fileCol" {
        return fileData.file
    } else if tableColumn!.identifier == "titleCol" {
        return fileData.title
    }

    return "N/A"
}

请注意,它不会尝试创建或返回视图。

这是第一步。表视图将获取您从该方法返回的对象值,并将其分配给您用作单元格视图的objectValue的{​​{1}}属性。但是,它本身并没有做任何事情。

有几种不同的方法可以让对象值实际显示在单元格视图中:

  • 使用文本字段本身,而不是使用NSTableCellView,每个包含文本字段作为单元格视图。由于NSTableCellView还具有NSTextField属性(继承自objectValue),因此表格视图可以设置对象值,并显示您的内容。缺点是您的单元格视图只是一个视图。如果您希望在每个单元格中看到多个视图,则无法使用此方法。
  • 继续使用NSControl作为您的单元格视图,就像您现在所做的那样。使用关键路径NSTableCellView将文本字段的值绑定绑定到包含NSTableCellView的值。这样,当表格设置objectValue的{​​{1}}时,它会自动传播到文本字段。
  • 通过直接设置文本字段属性的值来实现objectValue以配置单元格视图。基本上,这看起来就像你为NSTableCellView实施的内容。这有效地使您tableView(_:viewForTableColumn:row:)的实现变得多余。您需要实现它,表视图将调用它并使用结果来设置单元格视图的tableView(_:objectValueForTableColumn:row:),但这对单元格视图中的文本字段没有影响。
  • 使用tableView(_:objectValueForTableColumn:row:)的自定义子类,将objectValue属性观察者添加到NSTableCellView属性。这可以将新值转发给子视图。

就个人而言,我使用绑定方法。

此外,您应该考虑从didSet返回整个objectValue对象,而不是其中一个属性的值。因此,fileData对列不敏感,只对行敏感。每个tableView(_:objectValueForTableColumn:row:)的{​​{1}}将是相应的tableView(_:objectValueForTableColumn:row:)个实例。

然后,将调整文本字段与其封闭单元格视图的绑定,以选择objectValue的相应属性。例如,一列中的文本字段将绑定到其封闭的NSTableCellView,其关键路径为FilesListData。在另一列中,它将使用FilesListData的关键路径。

如果您的单元格视图最终会在其中包含多个视图时变得更加复杂,这将非常有用。每个视图都可以访问NSTableCellView对象的任何属性。使用当前只返回单个属性作为单元格对象值的方法,那么视图就只能处理这一个值。