应用程序因绑定到 Table 单元格视图而崩溃
App Crashes Due to Binding to Table Cell View
所以我创建了一个 NSOutlineView
来以分层方式显示文件和目录列表。我正在构建一个 BitTorrent 客户端(说明 class 名称有意义)。
如您所见,大纲视图大致如下所示:
问题与 Name 列有关。在名称列中,对于每一行,我都有一个并排的复选框和一个文本字段。这将帮助您更清楚地了解:
现在,我使用绑定来获取每个文本字段的值。但是,由于有 2 个视图(复选框和文本字段)需要绑定到相同的 NSTableCellView
,我从数据源返回一个包含 2 个值的结构:文本字段的字符串(包含file/directory 名称)和 enabling/disabling 复选框的布尔值。
为了处理大纲视图(尤其是其数据),我将其 class 设置为 TorrentContent
,其定义如下:
import Cocoa
struct Name {
let value: String
let enabled: Bool
}
class TorrentContent: NSOutlineView, NSOutlineViewDelegate, NSOutlineViewDataSource {
var content: [TorrentContentItem]
required init?(coder: NSCoder) {
let srcDir = TorrentContentItem("src")
let mainJava = TorrentContentItem("main.java")
let mainCpp = TorrentContentItem("main.cpp")
srcDir.children.append(mainJava)
srcDir.children.append(mainCpp)
content = [srcDir]
super.init(coder: coder)
delegate = self
dataSource = self
}
func outlineView(_: NSOutlineView, isItemExpandable item: Any) -> Bool {
if let _item = item as? TorrentContentItem {
if _item.children.count > 0 {
return true
} else {
return false
}
} else {
return false
}
}
func outlineView(_: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
if item == nil {
return content.count
} else {
if let _item = item as? TorrentContentItem {
return _item.children.count
}
}
return 0
}
func outlineView(_: NSOutlineView, child: Int, ofItem item: Any?) -> Any {
if item != nil {
if let _item = item as? TorrentContentItem {
return _item.children[child]
}
}
return content[child]
}
func outlineView(_: NSOutlineView, objectValueFor col: NSTableColumn?, byItem item: Any?) -> Any? {
if item != nil, col != nil {
if let _item = item as? TorrentContentItem {
switch col!.title {
case "Name":
return Name(value: _item.name, enabled: false)
default:
return nil
}
}
}
return nil
}
}
我有 hard-coded 数据,因此您可以更轻松地了解正在发生的事情。
仅关注名称列,这是上面代码中处理该列的部分:
func outlineView(_: NSOutlineView, objectValueFor col: NSTableColumn?, byItem item: Any?) -> Any? {
if item != nil, col != nil {
if let _item = item as? TorrentContentItem {
switch col!.title {
case "Name":
return Name(value: _item.name, enabled: false)
default:
return nil
}
}
}
return nil
}
如您所见,它 returns Name
结构,其中包含两个视图的值。我已将 hard-coded enabled 值设置为 false 仅用于测试目的。
现在将其绑定到文本字段的 值 属性,我这样做了:
我的逻辑是,由于 objectValue 是 Name
结构的一个实例,objectValue.value 应该是 Name
结构实例的 value,它是一个字符串。
我想以类似的方式绑定复选框的 enabled 属性。但是,none 的绑定有效。它们会导致应用程序崩溃。这是 XCode 在我每次尝试在运行时查看大纲视图时崩溃后显示的内容:
控制台中只有“(lldb)”。
我做错了什么,我该如何实现我想要的?即从数据源class.
设置多个视图的属性值
Cocoa Bindings使用Key Value Observing (KVO),被观察的对象必须是KVO兼容的。参见 Using Key-Value Observing in Swift。
You can only use key-value observing with classes that inherit from NSObject.
Mark properties that you want to observe through key-value observing with both the @objc attribute and the dynamic modifier.
解决方案 A:Return 来自 outlineView(_:objectValueFor:byItem:)
的 KVO 兼容对象
解决方案 B:不要使用 Cocoa 绑定。创建 NSTableCellView
的子类并添加 enabledCheckbox
插座。在 outlineView(_:viewFor:item:)
.
中设置值
所以我创建了一个 NSOutlineView
来以分层方式显示文件和目录列表。我正在构建一个 BitTorrent 客户端(说明 class 名称有意义)。
如您所见,大纲视图大致如下所示:
问题与 Name 列有关。在名称列中,对于每一行,我都有一个并排的复选框和一个文本字段。这将帮助您更清楚地了解:
现在,我使用绑定来获取每个文本字段的值。但是,由于有 2 个视图(复选框和文本字段)需要绑定到相同的 NSTableCellView
,我从数据源返回一个包含 2 个值的结构:文本字段的字符串(包含file/directory 名称)和 enabling/disabling 复选框的布尔值。
为了处理大纲视图(尤其是其数据),我将其 class 设置为 TorrentContent
,其定义如下:
import Cocoa
struct Name {
let value: String
let enabled: Bool
}
class TorrentContent: NSOutlineView, NSOutlineViewDelegate, NSOutlineViewDataSource {
var content: [TorrentContentItem]
required init?(coder: NSCoder) {
let srcDir = TorrentContentItem("src")
let mainJava = TorrentContentItem("main.java")
let mainCpp = TorrentContentItem("main.cpp")
srcDir.children.append(mainJava)
srcDir.children.append(mainCpp)
content = [srcDir]
super.init(coder: coder)
delegate = self
dataSource = self
}
func outlineView(_: NSOutlineView, isItemExpandable item: Any) -> Bool {
if let _item = item as? TorrentContentItem {
if _item.children.count > 0 {
return true
} else {
return false
}
} else {
return false
}
}
func outlineView(_: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
if item == nil {
return content.count
} else {
if let _item = item as? TorrentContentItem {
return _item.children.count
}
}
return 0
}
func outlineView(_: NSOutlineView, child: Int, ofItem item: Any?) -> Any {
if item != nil {
if let _item = item as? TorrentContentItem {
return _item.children[child]
}
}
return content[child]
}
func outlineView(_: NSOutlineView, objectValueFor col: NSTableColumn?, byItem item: Any?) -> Any? {
if item != nil, col != nil {
if let _item = item as? TorrentContentItem {
switch col!.title {
case "Name":
return Name(value: _item.name, enabled: false)
default:
return nil
}
}
}
return nil
}
}
我有 hard-coded 数据,因此您可以更轻松地了解正在发生的事情。
仅关注名称列,这是上面代码中处理该列的部分:
func outlineView(_: NSOutlineView, objectValueFor col: NSTableColumn?, byItem item: Any?) -> Any? {
if item != nil, col != nil {
if let _item = item as? TorrentContentItem {
switch col!.title {
case "Name":
return Name(value: _item.name, enabled: false)
default:
return nil
}
}
}
return nil
}
如您所见,它 returns Name
结构,其中包含两个视图的值。我已将 hard-coded enabled 值设置为 false 仅用于测试目的。
现在将其绑定到文本字段的 值 属性,我这样做了:
我的逻辑是,由于 objectValue 是 Name
结构的一个实例,objectValue.value 应该是 Name
结构实例的 value,它是一个字符串。
我想以类似的方式绑定复选框的 enabled 属性。但是,none 的绑定有效。它们会导致应用程序崩溃。这是 XCode 在我每次尝试在运行时查看大纲视图时崩溃后显示的内容:
控制台中只有“(lldb)”。
我做错了什么,我该如何实现我想要的?即从数据源class.
设置多个视图的属性值Cocoa Bindings使用Key Value Observing (KVO),被观察的对象必须是KVO兼容的。参见 Using Key-Value Observing in Swift。
You can only use key-value observing with classes that inherit from NSObject.
Mark properties that you want to observe through key-value observing with both the @objc attribute and the dynamic modifier.
解决方案 A:Return 来自 outlineView(_:objectValueFor:byItem:)
解决方案 B:不要使用 Cocoa 绑定。创建 NSTableCellView
的子类并添加 enabledCheckbox
插座。在 outlineView(_:viewFor:item:)
.