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

Kel*_*vin 7 cocoa nsoutlineview swift

我想在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
}
}
Run Code Online (Sandbox Code Playgroud)

示例项目可以在这里下载

cor*_*unn 8

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

return NSString(string: output)
Run Code Online (Sandbox Code Playgroud)

您正在返回一个快速释放的新NSString实例(因为大纲视图不会保留它).在那之后,任何时候你问问题都会导致崩溃,因为NSString已经被释放了.

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

科尔宾


Kel*_*vin 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")]]
Run Code Online (Sandbox Code Playgroud)

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