由于绑定到表单元格视图而导致应用程序崩溃

问题描述 投票:0回答:1

因此,我创建了一个NSOutlineView以分层显示文件和目录列表。我正在构建一个BitTorrent客户端(声明为类名有意义)。

您可以看到,这几乎就是轮廓视图的外观:

enter image description here

问题与名称列相关。在名称列中,每一行都有一个复选框和一个文本字段并排。这将帮助您获得更清晰的想法:

enter image description here

现在,我使用绑定来获取每个文本字段的值。但是,由于有两个视图(复选框和文本字段)需要绑定到相同的NSTableCellView,因此我从数据源返回一个结构,其中包含2个值:文本字段的字符串(用于保存文件) /目录名),以及用于启用/禁用复选框的布尔值。

为了处理大纲视图(尤其是其数据),我将其类设置为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
    }
}

我已经对数据进行了硬编码,因此您可以更轻松地了解发生了什么。

仅在名称列上,这是上面代码中涉及该部分的部分:

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
}

如您所见,它返回Name结构,其中包含两个视图的值。我已将enabled值硬编码为false,仅用于测试目的。

现在将其绑定到文本字段的value属性,我已经这样做:

enter image description here

我的逻辑是,由于objectValueName结构的实例,所以objectValue.value应该是Name结构的实例的value,它是一个字符串。

我想以类似方式绑定复选框的enabled属性。但是,所有绑定都不起作用。它们会导致应用崩溃。这是每次我在运行时尝试查看大纲视图时XCode崩溃后向我显示的内容:

enter image description here

在控制台中只有“(lldb)”。

我做错了什么,如何实现我想要的?也就是说,从数据源类设置多个视图的属性值。

swift xcode macos xcode11 appkit
1个回答
0
投票

可可绑定使用键值观察(KVO),并且观察到的对象必须与KVO兼容。参见Using Key-Value Observing in Swift

您只能对从NSObject继承的类使用键值观察。

用@objc属性和动态修饰符标记要通过键值观察观察的属性。

解决方案A:从outlineView(_:objectValueFor:byItem:)返回一个KVO兼容对象

解决方案B:不要使用可可绑定。创建NSTableCellView的子类并添加enabledCheckbox插座。在outlineView(_:viewFor:item:)中设置值。

© www.soinside.com 2019 - 2024. All rights reserved.