当isGroupItem委托方法与Swift一起使用时,NSOutlineView崩溃

时间:2014-12-11 13:38:06

标签: cocoa swift nsoutlineview

我想在Swift项目中使用NSOutlineView部署源列表。

下面的视图控制器在未调用isGroupItem委托方法时效果很好。但是,使用isGroupItem方法时将返回许多__NSMallocBlock__项。我不知道这些物品来自哪里。我提供的项目只是字符串。

class ViewController: NSViewController, NSOutlineViewDataSource, NSOutlineViewDelegate {

let topLevel = ["1", "2"]
let secLevel = ["1": ["1.1", "1.2"], "2": ["2.1", "2.2"]]

func outlineView(outlineView: NSOutlineView, numberOfChildrenOfItem item: AnyObject?) -> Int {
    if let str = item as? String {
        let arr = secLevel[str]! as [String]
        return arr.count
    } else {
        return topLevel.count
    }
}

func outlineView(outlineView: NSOutlineView, isItemExpandable item: AnyObject) -> Bool {
    return outlineView.parentForItem(item) == nil
}

func outlineView(outlineView: NSOutlineView, child index: Int, ofItem item: AnyObject?) -> AnyObject {
    var output: String!
    if let str = item as? String {
        output = secLevel[str]![index]
    } else {
        output = topLevel[index]
    }
    return NSString(string: output)
}

func outlineView(outlineView: NSOutlineView, objectValueForTableColumn tableColumn: NSTableColumn?, byItem item: AnyObject?) -> AnyObject? {
    return item
}

func outlineView(outlineView: NSOutlineView, isGroupItem item: AnyObject) -> Bool {
    return (outlineView.parentForItem(item) == nil)
}

func outlineView(outlineView: NSOutlineView, viewForTableColumn tableColumn: NSTableColumn?, item: AnyObject) -> NSView? {
    return outlineView.makeViewWithIdentifier("HeaderCell", owner: self) as NSTextField
}
}

可以下载示例项目here

3 个答案:

答案 0 :(得分:8)

如果您查看NSOutlineView文档,您将看到它只存储指针;它不保留从子进程返回的对象:ofItem:delegate方法。所以,当你这样做时:

return NSString(string: output)

您正在返回一个快速发布的新NSString实例(因为大纲视图不会保留它)。在那之后,任何时候你提出有关这些项目的问题都会导致崩溃,因为NSString已被释放。

解决方案很简单:将NSStrings存储在一个数组中,每次都返回相同的实例。

卡宾

答案 1 :(得分:5)

Ken Thomases在苹果开发者论坛上回答了这个问题。这里摘录了他所说的话:

  

您提供给大纲视图的项目必须是持久的。此外,您必须每次为给定的父级和索引返回相同的项目。你不能返回临时创建的对象,就像你在-outlineView中做的那样:child:ofItem:你调用NSString方便构造函数。

在持久保存数据源对象后,它可以正常工作:

let topLevel = [NSString(string: "1"), NSString(string: "2")]
let secLevel = ["1": [NSString(string: "1.1"), NSString(string: "1.2")], "2": [NSString(string: "2.1"), NSString(string: "2.2")]]

然后在outlineView:child:ofItem:datasource方法中返回存储的NSString。

答案 2 :(得分:0)

这是因为NSOutlineView适用于从NSObject继承的对象,而Swift字符串是不兼容的类型。