简体   繁体   English

尝试使用NSTableView

[英]Trying to use NSTableView

I'm an iOS dev and I'm creating my first Mac app. 我是iOS开发人员,正在创建我的第一个Mac应用程序。 Running into some difficulties when trying to use NSTableView. 尝试使用NSTableView时遇到一些困难。

extension HomeViewController:NSTableViewDataSource{
    func numberOfRows(in tableView: NSTableView) -> Int {
        print(self.customerApplicationList.count) // '1' gets printed here
        return self.customerApplicationList.count
    }

    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView?{
        var result:NSTableCellView
        result  = tableView.make(withIdentifier: "firstName", owner: self) as! NSTableCellView
        result.textField?.stringValue = "test"
        return result
    }
}

在此处输入图片说明

Why is there no cell showing up with the value "test" in there? 为什么没有显示带有“ test”值的单元格? (at run time, didn't include a screenshot of this) (在运行时,未提供此屏幕截图)

If you put a log in your tableView(_:viewFor:row:) method, you'll find out that it's never being called. 如果将日志放入tableView(_:viewFor:row:)方法中,则会发现它从未被调用过。 Why is this, you may wonder? 为什么会这样,您可能想知道? Well, it's complicated: 好吧,这很复杂:

AppKit, as we all know, is not implemented using Swift; 众所周知,AppKit不是使用Swift来实现的; it's implemented in Objective-C. 它是在Objective-C中实现的。 Objective-C, being a very dynamic language, allows a caller to query whether an object responds to a certain message, so all an object has to do is implement a method like -tableView:viewForTableColumn:row: , and through the magic of Objective-C, AppKit can find the method and call it. Objective-C是一种非常动态的语言,它允许调用者查询对象是否响应特定消息,因此,对象要做的就是实现-tableView:viewForTableColumn:row: ,并-tableView:viewForTableColumn:row: Objective -C,AppKit可以找到该方法并调用它。 With Swift, things are a little more complicated because, by default, Swift methods are not exposed to Objective-C, unless we explicitly make it so via the @objc keyword, if the method is an override of an Objective-C superclass method, or if the method satisfies an Objective-C protocol. 使用Swift时,事情要复杂一些,因为默认情况下,除非我们通过@objc关键字明确地使Swift方法不暴露于Objective-C,否则该方法将覆盖Objective-C超类方法,或者该方法满足Objective-C协议。 The third of these cases should occur here, except that it turns out that tableView(_:viewFor:row:) actually belongs to NSTableViewDelegate , not NSTableViewDataSource . 除了事实证明tableView(_:viewFor:row:)实际上属于NSTableViewDelegate而不是NSTableViewDataSource之外,这里应该发生第三种情况。 Therefore, the Swift compiler does not see your method as satisfying any protocol, and it is left unexposed to Objective-C. 因此,Swift编译器不会将您的方法视为满足任何协议,因此它不会暴露给Objective-C。 So from AppKit's point of view, it's as if you didn't implement it at all. 因此,从AppKit的角度来看,就好像您根本没有实现它。

To solve your immediate problem, add NSTableViewDelegate to your extension, and make sure your data source is set as the delegate in Interface Builder. 要解决您眼前的问题,请将NSTableViewDelegate添加到扩展中,并确保将数据源设置为Interface Builder中的委托。 However, when making Mac apps, I find it easier to use Cocoa Bindings to populate table views, as you get a lot of features "for free" such as automatic sorting by column, type-ahead selection, and selection management. 但是,在制作Mac应用程序时,我发现使用Cocoa绑定更容易填充表格视图,因为您可以“免费”获得许多功能,例如按列自动排序,预输入选择和选择管理。 To do this, follow these steps: 为此,请按照下列步骤操作:

1) Make sure the array property on your object is marked with both the @objc and the dynamic keyword, and that the class contained within the array is an NSObject subclass, and has its relevant properties also marked @objc and dynamic : 1)确保对象上的array属性同时标有@objcdynamic关键字,并且数组中包含的类是NSObject子类,并且其相关属性也标有@objcdynamic

class Thingy: NSObject {
    @objc dynamic var name: String

    init(name: String) { self.name = name }
}

class MyViewControllerThingy: NSViewController {
    @objc dynamic var myArray: [Thingy] = [Thingy(name: "Foo"), Thingy(name: "Bar")]
}

This makes sure that AppKit can do its dynamic Objective-C magic to automatically make this property KVO-compliant, so we don't have to do it ourselves (this is needed because Cocoa Bindings is built on KVO). 这可以确保AppKit可以执行其动态的Objective-C魔术来自动使该属性符合KVO,因此我们不必自己做(这是必需的,因为Cocoa Bindings是基于KVO构建的)。

2) Make an Array Controller in Interface Builder, and in the Bindings Inspector, set the Array Controller's "Model Key Path" to the name of your property: 2)在Interface Builder中创建一个Array Controller,然后在Bindings Inspector中,将Array Controller的“ Model Key Path”设置为属性的名称:

在此处输入图片说明

3) Now select your table view, and in its Bindings Inspector, bind its Content, Selection Indexes, and Sort Descriptors to arrangedObjects , selectionIndexes , and sortDescriptors respectively, leaving "Model Key Path" blank for each: 3)现在选择你的表视图,并在其绑定检查,结合它的内容,选择索引和排序描述符来arrangedObjectsselectionIndexessortDescriptors分别离开“模式键路径”空白每个:

在此处输入图片说明

4) Select your text field in the table view's cell, go to its Bindings Inspector, and bind it to the table cell view, with a Model Key Path of objectValue. 4)在表视图的单元格中选择文本字段,转到其Bindings Inspector,然后将其与objectValue.的模型键路径绑定到表单元格视图objectValue. and then the property name that you want to view in the cell: 然后要在单元格中查看的属性名称:

在此处输入图片说明

5) And finally, select the table column and set its Sort Key to the property name in the Attributes Inspector (the "Selector" field lets you customize what method to call on the objects to sort them; I like to use localizedStandardCompare: for strings to get case-insensitive sorting, but for most other types you can just leave this at the default): 5)最后,选择表列并将其Sort Key设置为Attributes Inspector中的属性名称(“ Selector”字段可让您自定义要对对象进行排序的方法;我喜欢对字符串使用localizedStandardCompare:以获得不区分大小写的排序,但是对于大多数其他类型,您可以将其保留为默认设置):

在此处输入图片说明

Et voilà: 等等:

在此处输入图片说明

This may seem like a lot of twiddling around in Interface Builder, but at the end of it we've set up the entire table with almost no code. 在Interface Builder中,这似乎有些混乱,但是到最后,我们几乎没有代码地设置了整个表。 And, we get a really slick UI for your users, along with a bunch of features for free, my favorite being automatic sorting by clicking on the headers: 而且,我们为您的用户提供了一个非常漂亮的用户界面,以及一些免费的功能,我最喜欢的功能是通过单击标题进行自动排序:

在此处输入图片说明

The great thing about this is not just that you don't have to bother with re-sorting the array yourself, but it doesn't even mess with the order of your original array; 这样做的好处不仅在于您不必费心自己对数组进行重新排序,而且它甚至不会弄乱原始数组的顺序。 the change is for display purposes only. 所做的更改仅用于显示目的。 The array here is still ["Foo", "Bar"] . 这里的数组仍然是["Foo", "Bar"]

Another really cool feature of NSArrayController is that it will manage the selection for you as well. NSArrayController另一个非常酷的功能是它将为您管理选择。 If your table view is a sidebar, for example, you can bind another view on the right to the selected object in the array controller, and this way you can easily implement things like Mail.app's pane viewer, including things like specifying placeholders to use if the user selects more than one object at once. 例如,如果表视图是侧边栏,则可以将右侧的另一个视图绑定到阵列控制器中所选对象,这样您就可以轻松实现Mail.app的窗格查看器之类的功能,包括指定要使用的占位符之类的内容。如果用户一次选择多个对象。 It's really slick. 真的很滑。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM